diff --git a/.gitignore b/.gitignore index 2f4e02babd6..c2059981ee5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ installs node_modules/ .travis.bak - +t.bat # Added for pedestal framework test .lein-deps-sum diff --git a/deployment/vagrant/Vagrantfile b/deployment/vagrant/Vagrantfile index cebf651a1b3..636f00a3a7f 100644 --- a/deployment/vagrant/Vagrantfile +++ b/deployment/vagrant/Vagrantfile @@ -13,6 +13,8 @@ Vagrant.configure("2") do |config| end config.vm.network "private_network", ip: "172.16.0.16" + config.vm.network "forwarded_port", guest: 5432, host: 5432 + config.vm.network "forwarded_port", guest: 3306, host: 3306 TCP_PORTS = [2001, 3000, 8000, 8080, 8081, 8082, 8085, 9000] diff --git a/frameworks/C++/aeronet/CMakeLists.txt b/frameworks/C++/aeronet/CMakeLists.txt new file mode 100644 index 00000000000..065d78f0a0a --- /dev/null +++ b/frameworks/C++/aeronet/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.23) +project(techempower_aeronet CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Fetch aeronet from GitHub +include(FetchContent) + +set(AERONET_GIT_TAG "main" CACHE STRING "Git tag/branch for aeronet") + +FetchContent_Declare( + aeronet + GIT_REPOSITORY https://github.com/sjanel/aeronet.git + GIT_TAG ${AERONET_GIT_TAG} + GIT_SHALLOW TRUE +) + +# Configure aeronet with minimal features for TechEmpower +set(AERONET_ENABLE_GLAZE ON CACHE BOOL "" FORCE) +set(AERONET_ENABLE_ASYNC_HANDLERS OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_HTTP2 OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_BROTLI OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_ZLIB OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_ZSTD OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_OPENSSL OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_OPENTELEMETRY OFF CACHE BOOL "" FORCE) +set(AERONET_ENABLE_WEBSOCKET OFF CACHE BOOL "" FORCE) +set(AERONET_BUILD_TESTS OFF CACHE BOOL "" FORCE) +set(AERONET_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set(AERONET_BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(aeronet) + +# TechEmpower benchmark executable +add_executable(benchmark_techempower main.cpp) +target_link_libraries(benchmark_techempower PRIVATE aeronet) + diff --git a/frameworks/C++/aeronet/README.md b/frameworks/C++/aeronet/README.md new file mode 100644 index 00000000000..2111949cac4 --- /dev/null +++ b/frameworks/C++/aeronet/README.md @@ -0,0 +1,16 @@ +# Aeronet (TechEmpower Framework Benchmarks) + +[aeronet](https://github.com/sjanel/aeronet) is a modern C++23 HTTP/1.1 + HTTP/2 server library focused on low overhead and high throughput. This TechEmpower implementation targets the JSON and Plaintext tests using glaze for fast JSON serialization. + +## Test Endpoints + +- `GET /json` -> `{"message":"Hello, World!"}` +- `GET /plaintext` -> `Hello, World!` + +## Notes + +- Built with C++23 and glaze 7.0.2. +- Linux-only (epoll-based). +- HTTP/1.1 keep-alive and pipelining supported. +- TLS, WebSocket, and HTTP/2 supported but not enabled in this benchmark. +- Other endpoints (e.g. database access) not implemented in this benchmark. diff --git a/frameworks/C++/aeronet/aeronet.dockerfile b/frameworks/C++/aeronet/aeronet.dockerfile new file mode 100644 index 00000000000..bb03297f4bc --- /dev/null +++ b/frameworks/C++/aeronet/aeronet.dockerfile @@ -0,0 +1,41 @@ +FROM ubuntu:24.04 AS build + +ARG AERONET_GIT_TAG=main +ARG BUILD_MODE=Release + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --no-install-recommends \ + build-essential \ + ninja-build \ + cmake \ + git \ + ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY main.cpp CMakeLists.txt ./ + +RUN mkdir build && cd build && \ + cmake -GNinja \ + -DCMAKE_BUILD_TYPE=${BUILD_MODE} \ + -DAERONET_GIT_TAG=${AERONET_GIT_TAG} \ + .. && \ + cmake --build . --target benchmark_techempower && \ + install -m 0755 benchmark_techempower /app/benchmark_techempower + +RUN mkdir -p /deps && \ + ldd /app/benchmark_techempower \ + | tr -s '[:blank:]' '\n' \ + | grep '^/' \ + | xargs -I % sh -c 'mkdir -p /deps$(dirname %); cp % /deps%;' + +FROM scratch + +COPY --from=build /etc/ssl/certs /etc/ssl/certs +COPY --from=build /deps / +COPY --from=build /app/benchmark_techempower /app/benchmark_techempower + +EXPOSE 8080 + +ENTRYPOINT ["/app/benchmark_techempower"] diff --git a/frameworks/C++/aeronet/benchmark_config.json b/frameworks/C++/aeronet/benchmark_config.json new file mode 100644 index 00000000000..2782ecd49af --- /dev/null +++ b/frameworks/C++/aeronet/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "aeronet", + "maintainers": [ "sjanel" ], + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "aeronet", + "language": "C++", + "orm": "Micro", + "platform": "Linux", + "webserver": "aeronet", + "os": "Linux", + "database_os": "Linux", + "dockerfile": "aeronet.dockerfile", + "notes": "Modern C++23 HTTP server with minimal overhead; JSON via glaze", + "versus": "" + } + } + ] +} diff --git a/frameworks/C++/aeronet/config.toml b/frameworks/C++/aeronet/config.toml new file mode 100644 index 00000000000..fc588fd1669 --- /dev/null +++ b/frameworks/C++/aeronet/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "aeronet" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "None" +webserver = "None" +versus = "None" diff --git a/frameworks/C++/aeronet/main.cpp b/frameworks/C++/aeronet/main.cpp new file mode 100644 index 00000000000..15e6284f446 --- /dev/null +++ b/frameworks/C++/aeronet/main.cpp @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +// TechEmpower Framework Benchmarks - Aeronet Implementation +// Implements Test 1 (JSON) and Test 6 (Plaintext) endpoints + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Test 1: JSON message structure +struct MessageResponse { + std::string_view message; +}; + +// Glaze metadata for JSON serialization +template <> +struct glz::meta { + using T = MessageResponse; + static constexpr auto value = glz::object("message", &T::message); +}; + +int main(int argc, char* argv[]) { + // Enable signal handler for graceful shutdown on Ctrl+C + aeronet::SignalHandler::Enable(); + + try { + using namespace aeronet; + + auto parseEnvUInt = [](const char* envVar) -> std::optional { + const char* value = std::getenv(envVar); + if (value == nullptr || value[0] == '\0') { + return std::nullopt; + } + uint32_t parsed = 0; + const auto [ptr, errc] = std::from_chars(value, value + std::strlen(value), parsed); + if (errc != std::errc{} || ptr != value + std::strlen(value)) { + return std::nullopt; + } + return parsed; + }; + + uint16_t port = 8080; + if (argc > 1) { + const auto [ptr, errc] = std::from_chars(argv[1], argv[1] + std::strlen(argv[1]), port); + if (errc != std::errc{} || ptr != argv[1] + std::strlen(argv[1])) { + std::cerr << "Invalid port number: " << argv[1] << "\n"; + return EXIT_FAILURE; + } + } + + HttpServerConfig config; + config.port = port; + if (const auto threads = parseEnvUInt("AERONET_THREADS"); threads.has_value()) { + config.nbThreads = *threads; + } else if (const auto threads = parseEnvUInt("THREADS"); threads.has_value()) { + config.nbThreads = *threads; + } + + Router router; + + // Test 6: Plaintext endpoint + // Returns a simple "Hello, World!" text response + router.setPath(http::Method::GET, "/plaintext", [](const HttpRequest& req) { + return req.makeResponse("Hello, World!", "text/plain; charset=UTF-8"); + }); + + // Test 1: JSON endpoint + router.setPath(http::Method::GET, "/json", [](const HttpRequest& req) { + MessageResponse msg{"Hello, World!"}; + return req.makeResponse(aeronet::SerializeToJson(msg), "application/json"); + }); + + // Health check endpoint (optional, useful for Docker) + router.setPath(http::Method::GET, "/health", + [](const HttpRequest& req) { return req.makeResponse("OK", "text/plain"); }); + + // Start the server + std::cout << "Starting TechEmpower benchmark server on port " << port << '\n'; + std::cout << " - JSON test (Test 1): GET /json\n"; + std::cout << " - Plaintext test (Test 6): GET /plaintext\n"; + std::cout << " - Health check: GET /health\n"; + + HttpServer server(config, std::move(router)); + server.run(); // blocking run, until Ctrl+C + + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << '\n'; + return 1; + } + + return 0; +} diff --git a/frameworks/C++/cpoll_cppsp/benchmark_config.json b/frameworks/C++/cpoll_cppsp/benchmark_config.json index 9917ee2d5d6..edc25b045eb 100644 --- a/frameworks/C++/cpoll_cppsp/benchmark_config.json +++ b/frameworks/C++/cpoll_cppsp/benchmark_config.json @@ -57,7 +57,8 @@ "database_os": "Linux", "display_name": "cpoll-cppsp-raw", "notes": "", - "versus": "cpoll_cppsp" + "versus": "cpoll_cppsp", + "tags": [ "broken" ] }, "postgres-raw-threadpool": { "db_url": "/db_pg_threadpool", diff --git a/frameworks/C++/cppcms/benchmark_config.json b/frameworks/C++/cppcms/benchmark_config.json index d4fbb4fa210..7be8b1750e1 100644 --- a/frameworks/C++/cppcms/benchmark_config.json +++ b/frameworks/C++/cppcms/benchmark_config.json @@ -40,7 +40,8 @@ "os": "Linux", "database_os": "Linux", "display_name": "CppCMS-PostgreSQL-nginx", - "notes": "" + "notes": "", + "tags": [ "broken" ] } }] } diff --git a/frameworks/C++/ffead-cpp/benchmark_config.json b/frameworks/C++/ffead-cpp/benchmark_config.json index 0a61221fc46..f2018153f62 100644 --- a/frameworks/C++/ffead-cpp/benchmark_config.json +++ b/frameworks/C++/ffead-cpp/benchmark_config.json @@ -47,7 +47,7 @@ "display_name": "ffead-cpp [v]", "notes": "", "versus": "", - "tags": [] + "tags": ["broken"] }, "v-picov-raw-profiled": { "json_url": "/t3/j", @@ -71,7 +71,7 @@ "display_name": "ffead-cpp [v-prof]", "notes": "", "versus": "", - "tags": [] + "tags": ["broken"] }, "v-picov-raw-clibpqb-profiled": { "json_url": "/t3/j", @@ -116,7 +116,7 @@ "display_name": "ffead-cpp [pg-raw-prof]", "notes": "memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] }, "postgresql-raw-clibpqb-profiled": { "db_url": "/t3/d", @@ -158,7 +158,7 @@ "display_name": "ffead-cpp [pg-raw-async-prof]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] }, "postgresql-raw-async-pool-profiled": { "db_url": "/t4/d", @@ -179,7 +179,7 @@ "display_name": "ffead-cpp [pg-raw-async-prof-pool]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] }, "postgresql-raw-async-pool-profiled-m": { "query_url": "/t4/quem?queries=", @@ -261,7 +261,7 @@ "display_name": "ffead-cpp [pg-raw-async-qw-prof]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] }, "postgresql-raw-async-qw-clibpqb-profiled": { "db_url": "/t5/d", diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index d6713a3e688..68f3d16d68d 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -1,4 +1,4 @@ -ARG UBUNTU_VERSION=25.10 +ARG UBUNTU_VERSION=26.04 ARG H2O_APP_PREFIX=/opt/h2o-app @@ -35,13 +35,14 @@ RUN apt-get install \ systemtap-sdt-dev RUN echo "[timing] Building H2O: $(date)" -ARG H2O_VERSION=3b9b6a53cac8bcc6a25fb28df81ad295fc5f9402 +ARG H2O_VERSION=ccea64b17ade832753db933658047ede9f31a380 WORKDIR /tmp/h2o-build RUN curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \ tar --strip-components=1 -xz && \ cmake \ -B build \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ -DWITH_MRUBY=on \ -S . && \ diff --git a/frameworks/C/octane/README.md b/frameworks/C/octane/README.md deleted file mode 100644 index 0f5e1f9272c..00000000000 --- a/frameworks/C/octane/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# OCTANE - -Benchmarks for the [octane](http://github.com/simongui/octane) library. diff --git a/frameworks/C/octane/benchmark_config.json b/frameworks/C/octane/benchmark_config.json deleted file mode 100644 index 3d0af9ec83b..00000000000 --- a/frameworks/C/octane/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "octane", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "port": 8000, - "approach": "Stripped", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "C", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "notes": "", - "versus": "octane", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/C/octane/config.toml b/frameworks/C/octane/config.toml deleted file mode 100644 index 161e013248d..00000000000 --- a/frameworks/C/octane/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "octane" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Stripped" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "octane" diff --git a/frameworks/C/octane/octane.dockerfile b/frameworks/C/octane/octane.dockerfile deleted file mode 100644 index adda06e128f..00000000000 --- a/frameworks/C/octane/octane.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential git cmake automake libtool wget - -WORKDIR /octane -RUN git clone https://github.com/simongui/octane.git . -RUN git checkout 8c28b1b83f1aa2817a401a3e8437a0af4ec53c28 -RUN rm -rf src/techempower_benchmarks -COPY src src/techempower_benchmarks - -RUN make - -ENV LD_PRELOAD /octane/lib/lockless_allocator/libllalloc.so.1.3 - -EXPOSE 8000 - -CMD ["./build/techempower_benchmarks"] diff --git a/frameworks/C/octane/src/program.cpp b/frameworks/C/octane/src/program.cpp deleted file mode 100644 index 9100f212e21..00000000000 --- a/frameworks/C/octane/src/program.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#include "responders/sds_responder.hpp" - -void timer_callback(uv_timer_t* timer); - -void on_request(http_connection* connection, http_request** requests, int number_of_requests); - -char* current_time; -uv_timer_t timer; - -int main(int argc, char *argv[]) { - http_listener* listener = new_http_listener(); - uv_timer_init(listener->loop, &timer); - uv_timer_start(&timer, timer_callback, 0, 500); - - begin_listening(listener, "0.0.0.0", 8000, false, 40, 128, NULL, NULL, NULL, on_request); - - printf("Listening...\n"); -} - -void on_request(http_connection* connection, http_request** requests, int number_of_requests) { - write_batch* batch = create_write_batch(number_of_requests); - - for (int i=0; ipath[1] == 'p') { - create_plaintext_response_sds(batch); - } else if (requests[i]->path[1] == 'j') { - create_json_response_sds(batch); - } - } - if (http_connection_is_writable(connection)) { - // TODO: Use the return values from uv_write() - int rc = http_connection_write(connection, batch); - } else { - // TODO: Handle closing the stream. - } - - free_http_requests(requests, number_of_requests); -} - -void timer_callback(uv_timer_t* timer) { - time_t curtime; - time(&curtime); - char* time = ctime(&curtime); - current_time = time; -} diff --git a/frameworks/C/octane/src/responders/sds_responder.cpp b/frameworks/C/octane/src/responders/sds_responder.cpp deleted file mode 100644 index 2a3825ddc53..00000000000 --- a/frameworks/C/octane/src/responders/sds_responder.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include "sds.h" -#include "sds_responder.hpp" -#include "rapidjson/writer.h" -#include "rapidjson/stringbuffer.h" - -using namespace rapidjson; - -extern char* current_time; - -const char* PLAINTEXT_CONTENT = "Hello, World!"; - -void create_plaintext_response_sds(write_batch* batch) { - sds response_buffer = sdsnew("HTTP/1.1 200 OK\r\n"); - response_buffer = sdscat(response_buffer, "Server: octane\r\n"); - response_buffer = sdscat(response_buffer, "Content-Type: text/plain\r\n"); - response_buffer = sdscatprintf(response_buffer, "Content-Length: %d\r\n", strlen(PLAINTEXT_CONTENT)); - response_buffer = sdscatprintf(response_buffer, "Date: %s\r\n", current_time); - response_buffer = sdscat(response_buffer, PLAINTEXT_CONTENT); - - batch->buffers[batch->number_of_used_buffers].base = response_buffer; - batch->buffers[batch->number_of_used_buffers].len = sdslen(response_buffer); - batch->number_of_used_buffers++; -} - -void create_json_response_sds(write_batch* batch) { - // Taken from H20 implementation. - // volatile is used to ensure that the object is instantiated every time - // the function is called. - const volatile struct { - const char *message; - } object = {PLAINTEXT_CONTENT}; - - StringBuffer s; - Writer writer(s); - writer.StartObject(); - writer.Key("message"); - writer.String((const char *)object.message, strlen(object.message)); - writer.EndObject(); - - sds response_buffer = sdsnew("HTTP/1.1 200 OK\r\n"); - response_buffer = sdscat(response_buffer, "Server: octane\r\n"); - response_buffer = sdscat(response_buffer, "Content-Type: application/json\r\n"); - response_buffer = sdscatprintf(response_buffer, "Content-Length: %d\r\n", s.GetSize()); - response_buffer = sdscatprintf(response_buffer, "Date: %s\r\n", current_time); - response_buffer = sdscat(response_buffer, s.GetString()); - - batch->buffers[batch->number_of_used_buffers].base = response_buffer; - batch->buffers[batch->number_of_used_buffers].len = sdslen(response_buffer); - batch->number_of_used_buffers++; -} diff --git a/frameworks/C/octane/src/responders/sds_responder.hpp b/frameworks/C/octane/src/responders/sds_responder.hpp deleted file mode 100644 index 4e31fb8b72e..00000000000 --- a/frameworks/C/octane/src/responders/sds_responder.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include -#include "octane.h" - -void create_plaintext_response_sds(write_batch* batch); -void create_json_response_sds(write_batch* batch); diff --git a/frameworks/C/onion/Makefile b/frameworks/C/onion/Makefile deleted file mode 100644 index badf4de9ba8..00000000000 --- a/frameworks/C/onion/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -.PHONY: all -all: hello - -CFLAGS=-O2 -Ionion/src/ - -hello: hello.o libonion_static.a base_html.o fortunes_html.o - cc hello.o base_html.o fortunes_html.o libonion_static.a -o hello -lpthread `mysql_config --libs` `pkg-config json --libs` -lgnutls -lgcrypt -lrt - -.PHONY: clean -clean: - rm -fr *.o hello base_html.c fortunes_html.c - -base_html.c: base.html - onion/build/tools/otemplate/otemplate base.html base_html.c - -fortunes_html.c: fortunes.html - onion/build/tools/otemplate/otemplate fortunes.html fortunes_html.c diff --git a/frameworks/C/onion/README b/frameworks/C/onion/README deleted file mode 100644 index 255bc6d1da5..00000000000 --- a/frameworks/C/onion/README +++ /dev/null @@ -1,7 +0,0 @@ -Makefile works for ubuntu. Other distros may need tweak. These extra packages are needed: - -libgnutls-dev -libmysqlclient-dev -libjson0-dev - -Any question or comment to dmoreno@coralbits.com. diff --git a/frameworks/C/onion/base.html b/frameworks/C/onion/base.html deleted file mode 100644 index 4ffc3ee1fb6..00000000000 --- a/frameworks/C/onion/base.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - {{title}} - - -{% block content %}No content{% endblock %} - - diff --git a/frameworks/C/onion/benchmark_config.json b/frameworks/C/onion/benchmark_config.json deleted file mode 100644 index 65e7f9fa09c..00000000000 --- a/frameworks/C/onion/benchmark_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "framework": "onion", - "tests": [{ - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortune", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "framework": "None", - "language": "C", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "onion", - "notes": "", - "versus": "onion", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/C/onion/config.toml b/frameworks/C/onion/config.toml deleted file mode 100644 index e30a2169394..00000000000 --- a/frameworks/C/onion/config.toml +++ /dev/null @@ -1,18 +0,0 @@ -[framework] -name = "onion" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.fortune = "/fortune" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "onion" diff --git a/frameworks/C/onion/fortunes.html b/frameworks/C/onion/fortunes.html deleted file mode 100644 index 1fc8cd250c5..00000000000 --- a/frameworks/C/onion/fortunes.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} -{% block content %} - - - - - -{% for f in fortunes %} - - - - -{% endfor %} -
idmessage
{{f.id}}{{f.message}}
-{% endblock %} - diff --git a/frameworks/C/onion/hello.c b/frameworks/C/onion/hello.c deleted file mode 100644 index 72f28a73241..00000000000 --- a/frameworks/C/onion/hello.c +++ /dev/null @@ -1,360 +0,0 @@ -// Compile it with: -// $ gcc -o bench bench.c -lonion -Wall -O2 -lsqlite3 -// $ export ONION_LOG=noinfo # To properly test, you may need some control over logging. Here almost disabled. -// $ ./bench -// It listens to localhost:8080, known addresses: http://localhost:8080/ , http://localhost:8080/db , http://localhost:8080/db20 -// Test it with ab: -// $ ab -k -t 10 -c 20 http://localhost:8080/ -// It gave me (Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz): -// Requests per second: 58288.10 [#/sec] (mean) - -// Done in response of http://www.techempower.com/blog/2013/03/28/framework-benchmarks/ -// Although onion is not a framework. - -// Copyright (c) 2013, David Moreno -// Under BSD license - -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// The views and conclusions contained in the software and documentation are those -// of the authors and should not be interpreted as representing official policies, -// either expressed or implied, of the FreeBSD Project. - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/// Gets the dict and converts it to JSON and writes it into the response. -onion_connection_status return_json(onion_dict *json, onion_request *req, onion_response *res){ - onion_block *bl=onion_dict_to_json(json); - size_t size=onion_block_size(bl); - onion_response_set_header(res, "Content-Type","application/json"); - onion_response_set_length(res, size); - onion_response_write(res, onion_block_data(bl), size); - onion_block_free(bl); - return OCS_PROCESSED; -} - -/// Gets the dict and converts it to JSON and writes it into the response. -onion_connection_status return_json_libjson(void *_, onion_request *req, onion_response *res){ - json_object *hello=json_object_new_object(); - json_object_object_add(hello, "message", json_object_new_string("Hello, World!")); - - const char *hello_str=json_object_to_json_string(hello); - int size=strlen(hello_str); - - onion_response_set_header(res, "Content-Type","application/json"); - onion_response_set_length(res, size); - onion_response_write(res, hello_str, size); - json_object_put(hello); - return OCS_PROCESSED; -} - -/// Do one sqlite petition -onion_connection_status return_db(MYSQL *db, onion_request *req, onion_response *res){ - char query[256]; - char *error; - const char *nqueries_str=onion_request_get_query(req,"queries"); - int queries=(nqueries_str) ? atoi(nqueries_str) : 1; - if (queries<=0) - queries=1; - else if (queries>500) - queries=500; - - json_object *json=json_object_new_object(); - json_object *array=json_object_new_array(); - int i; - for (i=0;imessage, b->message); -} - -onion_connection_status return_fortune(MYSQL *db, onion_request *req, onion_response *res){ - mysql_query(db, "SELECT id, message FROM Fortune;"); - MYSQL_RES *sqlres = mysql_store_result(db); - if (!sqlres) - return OCS_INTERNAL_ERROR; - MYSQL_ROW row; - fortune_list_t fortune_list; - - fortune_list.count=0; - fortune_list.size=16; - fortune_list.list=calloc(16,sizeof(fortune_t)); - - while( (row=mysql_fetch_row(sqlres)) ){ - if (fortune_list.count>=fortune_list.size){ - fortune_list.size+=fortune_list.size; - fortune_list.list=realloc(fortune_list.list, fortune_list.size * sizeof(fortune_list.size)); - } - strncpy(fortune_list.list[fortune_list.count].id,row[0],sizeof(fortune_list.list[fortune_list.count].id)); - strncpy(fortune_list.list[fortune_list.count].message,row[1],sizeof(fortune_list.list[fortune_list.count].message)); - fortune_list.count++; - } - if (fortune_list.count>=fortune_list.size){ - fortune_list.size+=fortune_list.size; - fortune_list.list=realloc(fortune_list.list, fortune_list.size * sizeof(fortune_list.size)); - } - strncpy(fortune_list.list[fortune_list.count].id,"0",sizeof(fortune_list.list[fortune_list.count].id)); - strncpy(fortune_list.list[fortune_list.count].message,"Additional fortune added at request time.",sizeof(fortune_list.list[fortune_list.count].message)); - fortune_list.count++; - - - qsort(fortune_list.list, fortune_list.count, sizeof(fortune_t), (__compar_fn_t)cmp_fortune); - - onion_dict *context=onion_dict_new(); - - onion_dict_add(context, "title", "Fortunes", 0); - - onion_dict *fortunes=onion_dict_new(); - int i; - for (i=0;isem); - pthread_mutex_lock(&data->mutex); - int i; - for (i=0;ifree_db[i]){ - data->free_db[i]=0; - pthread_mutex_unlock(&data->mutex); - return data->db[i]; - } - } - - pthread_mutex_unlock(&data->mutex); // I think it should never get here, but just in case - sem_post(&data->sem); - } -} - -void free_connection(struct test_data *data, MYSQL *db){ - int i; - for (i=0;idb[i]==db){ - pthread_mutex_lock(&data->mutex); - data->free_db[i]=1; - pthread_mutex_unlock(&data->mutex); - sem_post(&data->sem); - } - } -} - -onion_connection_status return_plaintext(onion_request *req, onion_response *res){ - onion_response_set_header(res, "Content-Type","text/plain"); - onion_response_write0(res, "Hello, World!"); - return OCS_PROCESSED; -} - -/// Multiplexes to the proper handler depending on the path. -/// As there is no proper database connection pool, take one connection randomly, and uses it. -onion_connection_status muxer(struct test_data *data, onion_request *req, onion_response *res){ - const char *path=onion_request_get_path(req); - if (strcmp(path, "")==0) - return return_json(data->hello, req, res); - if (strcmp(path, "json")==0) - return return_json_libjson(NULL, req, res); - - if (strcmp(path, "db")==0){ - MYSQL *db=get_connection(data); - int ret=return_one_db(db, req, res); - free_connection(data, db); - return ret; - } - if (strcmp(path, "queries")==0){ - MYSQL *db=get_connection(data); - int ret=return_db(db, req, res); - free_connection(data, db); - return ret; - } - if (strcmp(path, "fortune")==0){ - MYSQL *db=get_connection(data); - int ret=return_fortune(db, req, res); - free_connection(data, db); - return ret; - } - if (strcmp(path, "plaintext")==0){ - return return_plaintext(req, res); - } - - return OCS_INTERNAL_ERROR; -} - -onion *o=NULL; - -static void shutdown_server(int _){ - if (o) - onion_listen_stop(o); -} - - -/// Creates the onion http server, creates some server data, creates the handler, listens. -int main(void){ - signal(SIGINT,shutdown_server); - signal(SIGTERM,shutdown_server); - - o=onion_new(O_POOL); - - struct test_data data; - data.hello=onion_dict_new(); - - int i; - for (i=0;i + + + Exe + net10.0 + enable + enable + true + false + + + + true + true + + + + + + + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/Model.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/Model.cs new file mode 100644 index 00000000000..574123c3697 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/Model.cs @@ -0,0 +1,14 @@ +#pragma warning disable IDE1006,CS8981 +using System.Text.Json.Serialization; + +namespace AkazawaYun.Benchmark.Platform; + + +[JsonSerializable(typeof(JsonModel))] +public partial class AotJsonContext : JsonSerializerContext { } + + +public class JsonModel +{ + public string? message { get; set; } +} diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/MyBenchmarkReceptor.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/MyBenchmarkReceptor.cs new file mode 100644 index 00000000000..ef8e022eb63 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/MyBenchmarkReceptor.cs @@ -0,0 +1,44 @@ +using AkazawaYun.PRO7; + +namespace AkazawaYun.Benchmark.Platform; + +class MyBenchmarkReceptor : akaWebReceptorBenchmark +{ + readonly JsonModel JsonModel; + + public MyBenchmarkReceptor() + { + JsonModel = new() + { + message = "Hello, World!" + }; + } + + + public override async ValueTask SendJson(IHttpContext http) + { + await http.Slient.Send(DataJson_OnlyHeader); + akaJson.Text2Json(JsonModel, http.Slient.JsonSender); + } + public override ValueTask SendDb(IHttpContext http) + { + throw new NotImplementedException(); + } + public override ValueTask SendQueries(IHttpContext http) + { + throw new NotImplementedException(); + } + public override ValueTask SendUpdates(IHttpContext http) + { + throw new NotImplementedException(); + } + public override ValueTask SendCachedQueries(IHttpContext http) + { + throw new NotImplementedException(); + } + public override ValueTask SendFortunes(IHttpContext http) + { + throw new NotImplementedException(); + } + +} diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/Program.cs new file mode 100644 index 00000000000..3a0f794ad2b --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Core/Program.cs @@ -0,0 +1,20 @@ +using AkazawaYun.PRO7; + +namespace AkazawaYun.Benchmark.Platform; + +class Program +{ + static readonly akaWebBuilder builder; + + static Program() + { + akaLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2026.1.28, 只支持 /plaintext 和 /json"); + akaJson.Config(AotJsonContext.Default); + builder = akaWebBuilder.Shared.Build(new MyBenchmarkReceptor()); + } + static async Task Main() + { + await builder.Launch(); + await Task.Delay(-1); + } +} diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj index b2312be1bbb..a46900d8a8d 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj @@ -15,7 +15,7 @@ - + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs index ca9bb7c1362..e1d173f7f38 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs @@ -6,7 +6,6 @@ class MyBenchmarkReceptor : akaWebReceptorBenchmark { readonly JsonModel JsonModel; - public MyBenchmarkReceptor() { JsonModel = new() @@ -16,13 +15,10 @@ public MyBenchmarkReceptor() } - public override ValueTask SendPlaintext(IHttpContext http) - { - return base.SendPlaintext(http); - } public override async ValueTask SendJson(IHttpContext http) { await http.Slient.Send(DataJson_OnlyHeader); + akaJson.Text2Json(JsonModel, out ReadOnlyMemory json); await http.Slient.Send(json); } diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs index 9be953769c4..92b319622bd 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs @@ -1,20 +1,41 @@ using AkazawaYun.PRO7; +using AkazawaYun.PRO7.AkazawaYunWebInterceptor; namespace AkazawaYun.Benchmark.Platform; class Program { + const int port = 8080; static readonly akaWebBuilder builder; static Program() { - akaLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); - akaJson.Config(AotJsonContext.Default); - builder = akaWebBuilder.Shared.Build(new MyBenchmarkReceptor()); + akaLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2026.1.15, 只支持 /plaintext 和 /json"); + akaJson.Config(null, AotJsonContext.Default); + builder = akaWebBuilder.Shared.SetPort(port).SetDev(true) + .Add(() => new MyBenchmarkReceptor()) + .Add(() => new(port)) + .Build() + .Config(lis => lis.LogLevel = 0) + .Config(rcp => + { + rcp.ClearInterceptor(); + rcp.AddInterceptor(new akaWebInterceptorAllAsPost()); + }); } static async Task Main() { await builder.Launch(); + + akaLog.Inf("[API SELF-TEST]"); + string url = $"http://localhost:{port}/plaintext"; + akaLog.Inf(" REQ URL :" + url); + string res = await akaHttpClient.Shared.Get(url).FetchString(); + akaLog.Inf(" RES LEN :" + res.Length); + akaLog.Inf(" RES BODY:" + res); + akaLog.Inf("[OK, I WORK FINE]"); + + akaLog.Default = akaLog.Output.NoneButWar; await Task.Delay(-1); } } diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj index 452b23e493c..82fa9321ab4 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj @@ -15,7 +15,7 @@ - + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs index 049af6e21f3..6ecde06eaa1 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs @@ -4,7 +4,7 @@ namespace AkazawaYun.Benchmark.WebApi; -class Mysql : akzDbFactory +class Mysql : akaDbFactory { protected override DbConnection NewConnection() => new MySqlConnection(ConString); } diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Program.cs index ab7234e6f72..75cc348a0c7 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Program.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Program.cs @@ -2,52 +2,53 @@ using AkazawaYun.AOT; using AkazawaYun.PRO7; +using AkazawaYun.PRO7.AkazawaYunWebInterceptor; namespace AkazawaYun.Benchmark.WebApi; class Program : IPostFunctionWrapper { - static readonly akzWebBuilder builder; - static readonly akzDbFactory mysql; const int port = 8080; + static readonly akaWebBuilder builder; + static readonly akaDbFactory mysql; static Program() { - akzJson.Config(null, AotJsonContext.Default); - builder = akzWebBuilder.Shared.SetPort(port).SetDev() - .Add(() => null) + akaJson.Config(null, AotJsonContext.Default); + builder = akaWebBuilder.Shared.SetPort(port).SetDev() + .Add(() => null) .Build() - .Config(lis => lis.LogLevel = 0) - .Config(itc => + .Config(lis => lis.LogLevel = 0) + .Config(rcp => { - itc.ClearInterceptor(); - itc.AddInterceptor(new akzWebInterceptorAsPost()); + rcp.ClearInterceptor(); + rcp.AddInterceptor(new akaWebInterceptorAllAsPost()); }); - mysql = new akzDbBuilderII() + mysql = new akaDbBuilderII() .SetServer("tfb-database") - //.SetServer("localhost:3306") .SetUser("benchmarkdbuser") - //.SetUser("root") .SetPwd("benchmarkdbpass") + //.SetServer("localhost:3306") + //.SetUser("root") //.SetPwd("123456") .SetDatabase("hello_world") .SetCharset() - .SetOtherset() + .SetOtherset("Pooling=true;MaximumPoolSize=32767;SslMode=none;AllowPublicKeyRetrieval=true;") .Build(); } static async Task Main() { await builder.Launch(); - akzLog.Inf("[API SELF-TEST]"); + akaLog.Inf("[API SELF-TEST]"); string url = $"http://localhost:{port}/plaintext"; - akzLog.Inf(" REQ URL :" + url); - string res = await akzHttpClient.Shared.Get(url).FetchString(); - akzLog.Inf(" RES LEN :" + res.Length); - akzLog.Inf(" RES BODY:" + res); - akzLog.Inf("[OK, I WORK FINE]"); + akaLog.Inf(" REQ URL :" + url); + string res = await akaHttpClient.Shared.Get(url).FetchString(); + akaLog.Inf(" RES LEN :" + res.Length); + akaLog.Inf(" RES BODY:" + res); + akaLog.Inf("[OK, I WORK FINE]"); - akzLog.Default = akzLog.Output.NoneButWar; + akaLog.Default = akaLog.Output.NoneButWar; await Task.Delay(-1); } @@ -101,12 +102,3 @@ static int ParseCount(string queries) } } - -public class akzWebInterceptorAsPost : WebInterceptor -{ - public override ValueTask Intercept(IHttpContext http) - { - http.Method = "POST"; - return InterceptorHttpRes.No(); - } -} diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/WorldService.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/WorldService.cs index 8f996368ac5..83f11c89259 100644 --- a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/WorldService.cs +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/WorldService.cs @@ -5,14 +5,14 @@ namespace AkazawaYun.Benchmark.WebApi; class WorldService { static readonly int @id; - // SELECT id, randomNumber FROM world WHERE id=@id ; - public static readonly string SqlSelect = akzSqlinq.Query().Select(m => new + //public static readonly string SqlSelect = "SELECT id, randomNumber FROM world WHERE id=@id LIMIT 1 ;"; + public static readonly string SqlSelect = akaSqlinq.Query().Select(m => new { m.id, m.randomNumber, }).Where(m => m.id == @id).Build(); - // UPDATE world SET randomNumber=@randomNumber WHERE id=@id ; - public static readonly string SqlUpdate = akzSqlinq.Update().Set(m => new() + //public static readonly string SqlUpdate = "UPDATE world SET randomNumber=@randomNumber WHERE id=@id ;"; + public static readonly string SqlUpdate = akaSqlinq.Update().Set(m => new() { randomNumber = m.randomNumber, }).Where(m => m.id == @id).Build(); diff --git a/frameworks/CSharp/appmpower/README.md b/frameworks/CSharp/appmpower/README.md index 75ff21e1637..936e84a12d2 100644 --- a/frameworks/CSharp/appmpower/README.md +++ b/frameworks/CSharp/appmpower/README.md @@ -7,7 +7,7 @@ This includes tests for plaintext, json, db, queries, updates and fortune. **Language** -* C# 7.0 +* C# 14 **Platforms** diff --git a/frameworks/CSharp/appmpower/appmpower-ado-my.dockerfile b/frameworks/CSharp/appmpower/appmpower-ado-my.dockerfile new file mode 100644 index 00000000000..1edbf4d51f1 --- /dev/null +++ b/frameworks/CSharp/appmpower/appmpower-ado-my.dockerfile @@ -0,0 +1,30 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +RUN apt-get update +RUN apt-get -yqq install clang zlib1g-dev +RUN apt-get update + +WORKDIR /app +COPY src . +RUN dotnet publish -c Release -o out /p:AOTEXE=true /p:Database=mysql /p:Driver=ado + +# Construct the actual image that will run +FROM mcr.microsoft.com/dotnet/aspnet:10.0.3 AS runtime + +RUN apt-get update +RUN apt-get install -y unixodbc-dev unixodbc wget curl +RUN apt-get update + +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 + +ENV ASPNETCORE_URLS http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ + +#TEST: ./tfb --test appmpower-odbc-my --type db + +EXPOSE 8080 + +ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile new file mode 100644 index 00000000000..a8f2161b325 --- /dev/null +++ b/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile @@ -0,0 +1,31 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +RUN apt-get update +RUN apt-get -yqq install clang zlib1g-dev +RUN apt-get update + +WORKDIR /app +COPY src . +RUN dotnet publish -c Release -o out /p:AOTEXE=true /p:Database=postgresql /p:Driver=ado + + +# Construct the actual image that will run +FROM mcr.microsoft.com/dotnet/aspnet:10.0.3 AS runtime + +RUN apt-get update +RUN apt-get install -y unixodbc-dev unixodbc wget curl +RUN apt-get update + +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 + +ENV ASPNETCORE_URLS http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ + +#TEST: ./tfb --test appmpower-odbc-my --type db + +EXPOSE 8080 + +ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile index 9f3e85a6439..abffb0b11f3 100644 --- a/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile @@ -5,31 +5,29 @@ RUN apt-get update WORKDIR /app COPY src . -RUN dotnet publish -c Release -o out /p:Database=mysql +RUN dotnet publish -c Release -o out /p:AOTEXE=true /p:Database=mysql /p:Driver=odbc # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:10.0.1 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0.3 AS runtime RUN apt-get update -# The following installs standard versions unixodbc and pgsqlodbc -# unixodbc still needs to be installed even if compiled locally RUN apt-get install -y unixodbc-dev unixodbc wget curl RUN apt-get update WORKDIR /odbc #TODOGITHUB -RUN curl -L -o mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz https://downloads.mariadb.com/Connectors/odbc/connector-odbc-3.1.20/mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz -RUN tar -xvzf mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz -RUN cp mariadb-connector-odbc-3.1.20-debian-bookworm-amd64/lib/mariadb/libm* /usr/lib/ -RUN cp -r /odbc/mariadb-connector-odbc-3.1.20-debian-bookworm-amd64/lib/mariadb /usr/local/lib/mariadb -RUN rm mariadb-connector-odbc-3.1.20-debian-bookworm-amd64.tar.gz +RUN curl -L -o mariadb-connector-odbc-3.2.8-debian-bookworm-amd64.tar.gz https://dlm.mariadb.com/4551546/Connectors/odbc/connector-odbc-3.2.8/mariadb-connector-odbc-3.2.8-debian-bookworm-amd64.tar.gz +RUN tar -xvzf mariadb-connector-odbc-3.2.8-debian-bookworm-amd64.tar.gz +RUN cp mariadb-connector-odbc-3.2.8-debian-bookworm-amd64/lib/mariadb/libm* /usr/lib/ +RUN cp -r /odbc/mariadb-connector-odbc-3.2.8-debian-bookworm-amd64/lib/mariadb /usr/local/lib/mariadb +RUN rm mariadb-connector-odbc-3.2.8-debian-bookworm-amd64.tar.gz #TODOLOCAL -#RUN curl -L -o mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz https://downloads.mariadb.com/Connectors/odbc/connector-odbc-3.1.20/mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz -#RUN tar -xvzf mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz -#RUN cp mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64/lib/mariadb/libm* /usr/lib/ -#RUN cp -r /odbc/mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64/lib/mariadb /usr/local/lib/mariadb -#RUN rm mariadb-connector-odbc-3.1.20-debian-bookworm-aarch64.tar.gz +#RUN curl -L -o mariadb-connector-odbc-3.2.8-debian-bookworm-aarch64.tar.gz https://dlm.mariadb.com/4551541/Connectors/odbc/connector-odbc-3.2.8/mariadb-connector-odbc-3.2.8-debian-bookworm-aarch64.tar.gz +#RUN tar -xvzf mariadb-connector-odbc-3.2.8-debian-bookworm-aarch64.tar.gz +#RUN cp mariadb-connector-odbc-3.2.8-debian-bookworm-aarch64/lib/mariadb/libm* /usr/lib/ +#RUN cp -r /odbc/mariadb-connector-odbc-3.2.8-debian-bookworm-aarch64/lib/mariadb /usr/local/lib/mariadb +#RUN rm mariadb-connector-odbc-3.2.8-debian-bookworm-aarch64.tar.gz ENV PATH=/usr/local/unixODBC/bin:$PATH diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile index 56dfaba77bb..3ac00672459 100644 --- a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile @@ -4,14 +4,14 @@ RUN apt-get -yqq install clang zlib1g-dev WORKDIR /app COPY src . -RUN dotnet publish -c Release -o out /p:Database=postgresql +RUN dotnet publish -c Release -o out /p:AOTEXE=true /p:Database=postgresql /p:Driver=odbc # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:10.0.1 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:10.0.3 AS runtime RUN apt-get update RUN apt-get install -y unixodbc-dev unixodbc odbc-postgresql -# unixodbc still needs to be installed even if compiled locally +RUN apt-get update ENV PATH=/usr/local/unixODBC/bin:$PATH diff --git a/frameworks/CSharp/appmpower/appmpower.dockerfile b/frameworks/CSharp/appmpower/appmpower.dockerfile index abdc5cfcb7c..95be03141a3 100644 --- a/frameworks/CSharp/appmpower/appmpower.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower.dockerfile @@ -4,8 +4,7 @@ RUN apt-get -yqq install clang zlib1g-dev WORKDIR /app COPY src . -#RUN dotnet publish appMpower/appMpower.csproj -c Release -o out -RUN dotnet publish -c Release -o out +RUN dotnet publish -c Release -o out /p:AOTEXE=true # Construct the actual image that will run FROM mcr.microsoft.com/dotnet/aspnet:10.0.1 AS runtime diff --git a/frameworks/CSharp/appmpower/benchmark_config.json b/frameworks/CSharp/appmpower/benchmark_config.json index 46dc7e7c00f..af833b836f0 100644 --- a/frameworks/CSharp/appmpower/benchmark_config.json +++ b/frameworks/CSharp/appmpower/benchmark_config.json @@ -64,6 +64,50 @@ "display_name": "appMpower [aot-no-reflection,my,odbc]", "notes": "", "versus": "aspnetcore-minimal" + }, + "ado-pg": { + "db_url": "/db", + "query_url": "/queries?c=", + "update_url": "/updates?c=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?c=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "appmpower", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "appMpower [aot-no-reflection,pg,ado]", + "notes": "", + "versus": "aspnetcore-minimal" + }, + "ado-my": { + "db_url": "/db", + "query_url": "/queries?c=", + "update_url": "/updates?c=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?c=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "appmpower", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "appMpower [aot-no-reflection,my,ado]", + "notes": "", + "versus": "aspnetcore-minimal" } } ] diff --git a/frameworks/CSharp/appmpower/config.toml b/frameworks/CSharp/appmpower/config.toml index a3747682191..f13f601c0b5 100644 --- a/frameworks/CSharp/appmpower/config.toml +++ b/frameworks/CSharp/appmpower/config.toml @@ -44,4 +44,36 @@ os = "Linux" orm = "Raw" platform = ".NET" webserver = "Kestrel" +versus = "aspnetcore-minimal" + +[ado-pg] +urls.db = "/db" +urls.query = "/queries?c=" +urls.update = "/updates?c=" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-worlds?c=" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Kestrel" +versus = "aspnetcore-minimal" + +[ado-my] +urls.db = "/db" +urls.query = "/queries?c=" +urls.update = "/updates?c=" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-worlds?c=" +approach = "Realistic" +classification = "Micro" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Kestrel" versus = "aspnetcore-minimal" \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs index 0dfe4581906..9364b69fc6a 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs @@ -1,28 +1,29 @@ using System.Data; -using System.Data.Odbc; +using System.Data.Common; +using System.Threading.Tasks; namespace appMpower.Orm.Data { public class DbCommand : IDbCommand { - private OdbcCommand _odbcCommand; + private System.Data.Common.DbCommand _dbCommand; private DbConnection _dbConnection; public DbCommand(DbConnection dbConnection) { - _odbcCommand = (OdbcCommand)dbConnection.CreateCommand(); + _dbCommand = (System.Data.Common.DbCommand)dbConnection.CreateCommand(); _dbConnection = dbConnection; } public DbCommand(string commandText, DbConnection dbConnection) { - _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text); + _dbCommand = dbConnection.GetCommand(commandText, CommandType.Text); _dbConnection = dbConnection; } public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection) { - _odbcCommand = dbConnection.GetCommand(commandText, commandType); + _dbCommand = dbConnection.GetCommand(commandText, commandType); _dbConnection = dbConnection; } @@ -30,11 +31,11 @@ internal IDbCommand Command { get { - return _odbcCommand; + return _dbCommand; } set { - _odbcCommand = (OdbcCommand)value; + _dbCommand = (System.Data.Common.DbCommand)value; } } @@ -42,11 +43,11 @@ public string CommandText { get { - return _odbcCommand.CommandText; + return _dbCommand.CommandText; } set { - _odbcCommand.CommandText = value; + _dbCommand.CommandText = value; } } @@ -54,22 +55,22 @@ public int CommandTimeout { get { - return _odbcCommand.CommandTimeout; + return _dbCommand.CommandTimeout; } set { - _odbcCommand.CommandTimeout = value; + _dbCommand.CommandTimeout = value; } } public CommandType CommandType { get { - return _odbcCommand.CommandType; + return _dbCommand.CommandType; } set { - _odbcCommand.CommandType = value; + _dbCommand.CommandType = value; } } @@ -78,11 +79,11 @@ public IDbConnection? Connection { get { - return _odbcCommand.Connection; + return _dbCommand.Connection; } set { - _odbcCommand.Connection = (OdbcConnection?)value; + _dbCommand.Connection = (System.Data.Common.DbConnection?)value; } } #nullable disable @@ -91,7 +92,7 @@ public IDataParameterCollection Parameters { get { - return _odbcCommand.Parameters; + return _dbCommand.Parameters; } } @@ -100,11 +101,11 @@ public IDbTransaction? Transaction { get { - return _odbcCommand.Transaction; + return _dbCommand.Transaction; } set { - _odbcCommand.Transaction = (OdbcTransaction?)value; + _dbCommand.Transaction = (System.Data.Common.DbTransaction?)value; } } #nullable disable @@ -113,90 +114,90 @@ public UpdateRowSource UpdatedRowSource { get { - return _odbcCommand.UpdatedRowSource; + return _dbCommand.UpdatedRowSource; } set { - _odbcCommand.UpdatedRowSource = value; + _dbCommand.UpdatedRowSource = value; } } public void Cancel() { - _odbcCommand.Cancel(); + _dbCommand.Cancel(); } public IDbDataParameter CreateParameter() { - return _odbcCommand.CreateParameter(); + return _dbCommand.CreateParameter(); } - public IDbDataParameter CreateParameter(string name, object value) + public DbParameter CreateParameter(string name, object value) { return CreateParameter(name, DbType.String, value); } - public IDbDataParameter CreateParameter(string name, DbType dbType, object value) + public DbParameter CreateParameter(string name, DbType dbType, object value) { - IDbDataParameter dbDataParameter; + DbParameter dbParameter; - if (_odbcCommand.Parameters.Contains(name)) + if (_dbCommand.Parameters.Contains(name)) { - dbDataParameter = _odbcCommand.Parameters[name]; - dbDataParameter.Value = value; + dbParameter = _dbCommand.Parameters[name]; + dbParameter.Value = value; } else { - dbDataParameter = _odbcCommand.CreateParameter(); + dbParameter = _dbCommand.CreateParameter(); - dbDataParameter.ParameterName = name; - dbDataParameter.DbType = dbType; - dbDataParameter.Value = value; - _odbcCommand.Parameters.Add(dbDataParameter); + dbParameter.ParameterName = name; + dbParameter.DbType = dbType; + dbParameter.Value = value; + _dbCommand.Parameters.Add(dbParameter); } - return dbDataParameter; + return dbParameter; } public int ExecuteNonQuery() { - return _odbcCommand.ExecuteNonQuery(); + return _dbCommand.ExecuteNonQuery(); } public IDataReader ExecuteReader() { - return _odbcCommand.ExecuteReader(); + return _dbCommand.ExecuteReader(); } public async Task ExecuteNonQueryAsync() { - return await _odbcCommand.ExecuteNonQueryAsync(); + return await _dbCommand.ExecuteNonQueryAsync(); } public IDataReader ExecuteReader(CommandBehavior behavior) { - return _odbcCommand.ExecuteReader(behavior); + return _dbCommand.ExecuteReader(behavior); } public async Task ExecuteReaderAsync(CommandBehavior behavior) { - return await _odbcCommand.ExecuteReaderAsync(behavior); + return await _dbCommand.ExecuteReaderAsync(behavior); } #nullable enable public object? ExecuteScalar() { - return _odbcCommand.ExecuteScalar(); + return _dbCommand.ExecuteScalar(); } #nullable disable public void Prepare() { - _odbcCommand.Prepare(); + _dbCommand.Prepare(); } public void Dispose() { - _dbConnection.Release(_odbcCommand); + _dbConnection.Release(_dbCommand); } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs index 7175e1119b4..ff6fb04bf4c 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs @@ -1,17 +1,20 @@ using System.Collections.Concurrent; +using System.Collections.Generic; using System.Data; -using System.Data.Odbc; +using System.Threading.Tasks; namespace appMpower.Orm.Data { public class DbConnection : IDbConnection { private string _connectionString; + private System.Data.Common.DbConnection _dbConnection; +#if ODBC private bool _keyed = false; private int _number; - private OdbcConnection _odbcConnection; - private ConcurrentStack _odbcCommands = new(); - private Dictionary _keyedOdbcCommands; + private ConcurrentStack _dbCommands = new(); + private Dictionary _keyedDbCommands; +#endif public DbConnection() { @@ -19,20 +22,25 @@ public DbConnection() public DbConnection(string connectionString, bool keyed = false) { + _connectionString = connectionString; + +#if ODBC _keyed = keyed; - _connectionString = connectionString; GetConnection(); +#else + _dbConnection = DbFactory.GetConnection(_connectionString); +#endif } public IDbConnection Connection { get { - return _odbcConnection; + return _dbConnection; } set { - _odbcConnection = (OdbcConnection)value; + _dbConnection = (System.Data.Common.DbConnection)value; } } @@ -40,34 +48,38 @@ public string ConnectionString { get { - return _odbcConnection.ConnectionString; + return _dbConnection.ConnectionString; } set { _connectionString = value; +#if ODBC GetConnection(); +#endif } } +#if ODBC private void GetConnection() { if (_keyed) { - (_number, _odbcConnection, _keyedOdbcCommands) = - DbConnectionsKeyed.GetConnectionBase(_connectionString); + (_number, _dbConnection, _keyedDbCommands) = + DbConnectionsKeyed.GetConnectionBase(); } else { - (_number, _odbcConnection, _odbcCommands) = - DbConnections.GetConnectionBase(_connectionString); + (_number, _dbConnection, _dbCommands) = + DbConnections.GetConnectionBase(); } } +#endif public int ConnectionTimeout { get { - return _odbcConnection.ConnectionTimeout; + return _dbConnection.ConnectionTimeout; } } @@ -75,7 +87,7 @@ public string Database { get { - return _odbcConnection.Database; + return _dbConnection.Database; } } @@ -83,92 +95,103 @@ public ConnectionState State { get { - if (_odbcConnection is null) return ConnectionState.Closed; - return _odbcConnection.State; + if (_dbConnection is null) return ConnectionState.Closed; + return _dbConnection.State; } } public IDbTransaction BeginTransaction() { - return _odbcConnection.BeginTransaction(); + return _dbConnection.BeginTransaction(); } public IDbTransaction BeginTransaction(IsolationLevel il) { - return _odbcConnection.BeginTransaction(il); + return _dbConnection.BeginTransaction(il); } public void ChangeDatabase(string databaseName) { - _odbcConnection.ChangeDatabase(databaseName); + _dbConnection.ChangeDatabase(databaseName); } public void Close() { - _odbcConnection.Close(); + _dbConnection.Close(); } public IDbCommand CreateCommand() { - return _odbcConnection.CreateCommand(); + return _dbConnection.CreateCommand(); } public void Open() { - if (_odbcConnection.State == ConnectionState.Closed) + if (_dbConnection.State == ConnectionState.Closed) { - _odbcConnection.Open(); + _dbConnection.Open(); } } public async Task OpenAsync() { - if (_odbcConnection.State == ConnectionState.Closed) + if (_dbConnection.State == ConnectionState.Closed) { - await _odbcConnection.OpenAsync(); + await _dbConnection.OpenAsync(); } } public void Dispose() { +#if ODBC if (_keyed) { - DbConnectionsKeyed.Release((Number: _number, OdbcConnection: _odbcConnection, KeyedOdbcCommands: _keyedOdbcCommands)); + DbConnectionsKeyed.Release((Number: _number, DbConnection: _dbConnection, KeyedDbCommands: _keyedDbCommands)); } else { - DbConnections.Release((Number: _number, OdbcConnection: _odbcConnection, OdbcCommands: _odbcCommands)); + DbConnections.Release((Number: _number, DbConnection: _dbConnection, DbCommands: _dbCommands)); } +#else + _dbConnection.Dispose(); +#endif } - internal OdbcCommand GetCommand(string commandText, CommandType commandType) + internal System.Data.Common.DbCommand GetCommand(string commandText, CommandType commandType) { - OdbcCommand odbcCommand; + System.Data.Common.DbCommand dbCommand; - if (_odbcCommands.TryPop(out odbcCommand)) +#if ODBC + if (_dbCommands.TryPop(out dbCommand)) { - if (commandText != odbcCommand.CommandText) + if (commandText != dbCommand.CommandText) { - odbcCommand.CommandText = commandText; - odbcCommand.Parameters.Clear(); + dbCommand.CommandText = commandText; + dbCommand.Parameters.Clear(); } - return odbcCommand; + return dbCommand; } - else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) return odbcCommand; + else if (_keyed && _keyedDbCommands.TryGetValue(commandText, out dbCommand)) return dbCommand; +#endif + + dbCommand = _dbConnection.CreateCommand(); + dbCommand.CommandText = commandText; + dbCommand.CommandType = commandType; - odbcCommand = _odbcConnection.CreateCommand(); - odbcCommand.CommandText = commandText; - odbcCommand.CommandType = commandType; - odbcCommand.Prepare(); +#if !(ADO && POSTGRESQL) + dbCommand.Prepare(); +#endif - return odbcCommand; + return dbCommand; } - internal void Release(OdbcCommand odbcCommand) + internal void Release(System.Data.Common.DbCommand dbCommand) { - if (_keyed) _keyedOdbcCommands.TryAdd(odbcCommand.CommandText, odbcCommand); - else _odbcCommands.Push(odbcCommand); +#if ODBC + if (_keyed) _keyedDbCommands.TryAdd(dbCommand.CommandText, dbCommand); + else _dbCommands.Push(dbCommand); +#endif } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs index 8897db571fc..535bc90a728 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs @@ -1,5 +1,5 @@ +#if ODBC using System.Collections.Concurrent; -using System.Data.Odbc; namespace appMpower.Orm.Data { @@ -7,24 +7,27 @@ internal static class DbConnections { private static short _createdConnections = 0; - private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)> _connectionsStack = new(); + private static ConcurrentStack<(int Number, System.Data.Common.DbConnection DbConnection, ConcurrentStack DbCommands)> _connectionsStack = new(); - internal static (int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) GetConnectionBase(string connectionString) + internal static (int Number, System.Data.Common.DbConnection DbConnection, ConcurrentStack DbCommands) GetConnectionBase() { - (int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) dbConnectionBase; + (int Number, System.Data.Common.DbConnection DbConnection, ConcurrentStack DbCommands) dbConnectionBase; if (!_connectionsStack.TryPop(out dbConnectionBase)) { _createdConnections++; - dbConnectionBase = (Number: _createdConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack()); + dbConnectionBase = (Number: _createdConnections, + DbConnection: DbFactory.GetConnection(), + DbCommands: new ConcurrentStack()); } return dbConnectionBase; } - internal static void Release((int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) dbConnectionBase) + internal static void Release((int Number, System.Data.Common.DbConnection DbConnection, ConcurrentStack DbCommands) dbConnectionBase) { _connectionsStack.Push(dbConnectionBase); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs index 0779d640192..d07488b223b 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs @@ -1,5 +1,6 @@ +#if ODBC using System.Collections.Concurrent; -using System.Data.Odbc; +using System.Collections.Generic; namespace appMpower.Orm.Data { @@ -7,24 +8,27 @@ internal static class DbConnectionsKeyed { private static short _createdConnections = 0; - private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, Dictionary)> _connectionsStack = new(); + private static ConcurrentStack<(int Number, System.Data.Common.DbConnection DbConnection, Dictionary)> _connectionsStack = new(); - internal static (int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) GetConnectionBase(string connectionString) + internal static (int Number, System.Data.Common.DbConnection DbConnection, Dictionary KeyedDbCommands) GetConnectionBase() { - (int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) dbConnectionBase; + (int Number, System.Data.Common.DbConnection DbConnection, Dictionary KeyedDbCommands) dbConnectionBase; if (!_connectionsStack.TryPop(out dbConnectionBase)) { _createdConnections++; - dbConnectionBase = (Number: _createdConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary()); + dbConnectionBase = (Number: _createdConnections, + DbConnection: DbFactory.GetConnection(), + KeyedDbCommands: new Dictionary()); } return dbConnectionBase; } - internal static void Release((int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) dbConnectionBase) + internal static void Release((int Number, System.Data.Common.DbConnection DbConnection, Dictionary KeyedDbCommands) dbConnectionBase) { _connectionsStack.Push(dbConnectionBase); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbFactory.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbFactory.cs new file mode 100644 index 00000000000..72362b35407 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbFactory.cs @@ -0,0 +1,53 @@ +using System; +using System.Data.Common; + +namespace appMpower.Orm.Data +{ + public static class DbFactory + { + public static string ConnectionString; + public static DbProviderFactory Instance; + + public static System.Data.Common.DbConnection GetConnection(string connectionString = null) + { + System.Data.Common.DbConnection dbConnection = Instance.CreateConnection(); + dbConnection.ConnectionString = connectionString ?? ConnectionString; + + return dbConnection; + } + + public static void SetConnectionString() + { +#if ODBC + #if MYSQL + ConnectionString = "Driver={MariaDB};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;Pooling=false;OPTIONS=67108864;FLAG_FORWARD_CURSOR=1;sslmode=DISABLED;CharSet=utf8;"; + Console.WriteLine("hey odbc mysql"); + #else + ConnectionString = "Driver={PostgreSQL};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false;sslmode=disable"; + Console.WriteLine("hey odbc postgresql"); + #endif +#else + #if MYSQL + ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;SslMode=None;ConnectionReset=false;ConnectionIdlePingTime=900;ConnectionIdleTimeout=0;AutoEnlist=false;DefaultCommandTimeout=0;ConnectionTimeout=0;IgnorePrepare=false;"; + Console.WriteLine("hey ado mysql"); + #else + ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3;"; + Console.WriteLine("hey ado postgresql"); + #endif +#endif + } + + public static void SetInstance() + { +#if ODBC + Instance = System.Data.Odbc.OdbcFactory.Instance; +#else + #if MYSQL + Instance = MySqlConnector.MySqlConnectorFactory.Instance; + #elif POSTGRESQL + Instance = Npgsql.NpgsqlFactory.Instance; + #endif +#endif + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs deleted file mode 100644 index 1e72d164a25..00000000000 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Data; - -namespace appMpower.Orm.Data -{ - public static class DbProviderFactory - { - public static string ConnectionString; - - public static void SetConnectionString() - { - if (Constants.Dbms == Dbms.MySQL) - { - ConnectionString = "Driver={MariaDB};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;Pooling=false;OPTIONS=67108864;FLAG_FORWARD_CURSOR=1;sslmode=DISABLED;CharSet=utf8;"; - } - else - { - ConnectionString = "Driver={PostgreSQL};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false;sslmode=disable"; - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs index 5ea4ce43fa2..2523c762bdb 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs @@ -1,13 +1,17 @@ -using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Text; -using System.Text.Json; -using appMpower.Orm.Data; +using System.Text.Json; +using System.Threading.Tasks; +using appMpower.Orm.Data; using appMpower.Orm.Objects; using appMpower.Orm.Serializers; namespace appMpower.Orm; -//These methods are for test purposes only; not used in actual execution +#if !AOTDLL + public static class DotnetMethods { private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions @@ -19,9 +23,35 @@ public static class DotnetMethods private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); private readonly static WorldsSerializer _worldsSerializer = new WorldsSerializer(); - public static byte[] Db() + public static void Dbms(int dbms) + { + Constants.Dbms = (Dbms)dbms; + DbFactory.SetConnectionString(); + DbFactory.SetInstance(); + } + + public static void DbProvider(int dbProvider) + { + Constants.DbProvider = (DbProvider)dbProvider; + DbFactory.SetConnectionString(); + DbFactory.SetInstance(); + } + + public static async Task Db() + { + var world = await RawDb.LoadSingleQueryRowAsync(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + return memoryStream.ToArray(); + } + + public static async Task DbById(int id) { - var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); + var world = await RawDb.LoadSingleQueryRowByIdAsync(id); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -31,9 +61,9 @@ public static byte[] Db() return memoryStream.ToArray(); } - public static byte[] Query(int queries) + public static async Task Query(int queries) { - World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult(); + World[] worlds = await RawDb.LoadMultipleQueriesRowsAsync(queries); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -43,9 +73,9 @@ public static byte[] Query(int queries) return memoryStream.ToArray(); } - public static byte[] Updates(int count) + public static async Task Updates(int count) { - World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult(); + World[] worlds = await RawDb.LoadMultipleUpdatesRowsAsync(count); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -55,12 +85,14 @@ public static byte[] Updates(int count) return memoryStream.ToArray(); } - public static byte[] Fortunes() + public static async Task Fortunes() { - List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); + List fortunes = await RawDb.LoadFortunesRowsAsync(); string fortunesView = FortunesView.Render(fortunes); byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); return byteArray.ToArray(); } -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs index a5887f50142..0f3e501c485 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs @@ -1,8 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using appMpower.Orm; -using appMpower.Orm.Data; +using System.Linq; namespace PlatformBenchmarks { @@ -34,32 +33,51 @@ public static string Query(int batchSize) //sb.Append("(?::int,?::int)) AS temp(id, randomNumber) WHERE temp.id = world.id"); */ - if (Constants.Dbms == Dbms.MySQL) +#if MYSQL + for (int i = 0; i < batchSize; i++) { - for (int i = 0; i < batchSize; i++) - { - sb.Append("UPDATE world SET randomNumber=? WHERE id=?;"); - } + sb.Append("UPDATE world SET randomNumber=? WHERE id=?;"); } - else +#elif ADO + /* + sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES "); + Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@i{i}, @r{i}), ")); + sb.Append($"(@i{lastIndex}, @r{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); + */ + + sb.Append("UPDATE world SET randomNumber=CASE id "); + + for (int i = 0; i < batchSize; i++) + { + sb.Append("WHEN @i" + i + " THEN @r" + i + " "); + } + + sb.Append("ELSE randomnumber END WHERE id IN("); + + for (int i = 0; i < lastIndex; i++) { - sb.Append("UPDATE world SET randomNumber=CASE id "); + sb.Append("@j" + i + ","); + } - for (int i = 0; i < batchSize; i++) - { - sb.Append("WHEN ? THEN ? "); - } + sb.Append("@j" + lastIndex + ")"); +#else + sb.Append("UPDATE world SET randomNumber=CASE id "); - sb.Append("ELSE randomnumber END WHERE id IN("); + for (int i = 0; i < batchSize; i++) + { + sb.Append("WHEN ? THEN ? "); + } - for (int i = 0; i < lastIndex; i++) - { - sb.Append("?,"); - } + sb.Append("ELSE randomnumber END WHERE id IN("); - sb.Append("?)"); + for (int i = 0; i < lastIndex; i++) + { + sb.Append("?,"); } + sb.Append("?)"); +#endif + return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb); } } diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs index 374c9f4e1bb..b5a74d48884 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs @@ -1,7 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Runtime.CompilerServices; +using System.Threading; namespace PlatformBenchmarks { diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs index 73b890db750..db4a3bba80a 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Text; namespace PlatformBenchmarks; diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs index bdeb98565a5..93a1785322f 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs @@ -1,4 +1,8 @@ -using System.Runtime.InteropServices; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using appMpower.Orm.Data; @@ -7,6 +11,8 @@ namespace appMpower.Orm; +#if AOTDLL + public static class NativeMethods { private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions @@ -15,24 +21,25 @@ public static class NativeMethods SkipValidation = true }; - private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); - private readonly static WorldsSerializer _worldsSerializer = new WorldsSerializer(); - private readonly static FortunesSerializer _fortunesSerializer = new FortunesSerializer(); + private readonly static WorldSerializer _worldSerializer = new(); + private readonly static WorldsSerializer _worldsSerializer = new(); + private readonly static FortunesSerializer _fortunesSerializer = new(); private static readonly byte[] _delimiter = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }; - [UnmanagedCallersOnly(EntryPoint = "Dbms")] public static void Dbms(int dbms) { Constants.Dbms = (Dbms)dbms; - DbProviderFactory.SetConnectionString(); + DbFactory.SetConnectionString(); + DbFactory.SetInstance(); } [UnmanagedCallersOnly(EntryPoint = "DbProvider")] public static void DbProvider(int dbProvider) { Constants.DbProvider = (DbProvider)dbProvider; - DbProviderFactory.SetConnectionString(); + DbFactory.SetConnectionString(); + DbFactory.SetInstance(); } [UnmanagedCallersOnly(EntryPoint = "FreeHandlePointer")] @@ -45,7 +52,7 @@ public static void FreeHandlePointer(IntPtr handlePointer) [UnmanagedCallersOnly(EntryPoint = "Db")] public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) { - var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); + var world = RawDb.LoadSingleQueryRow(); var memoryStream = new MemoryStream(); using (var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions)) @@ -66,11 +73,10 @@ public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) return handle.AddrOfPinnedObject(); } - /* [UnmanagedCallersOnly(EntryPoint = "Fortunes")] public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) { - List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); + List fortunes = RawDb.LoadFortunesRows(); string fortunesView = FortunesView.Render(fortunes); byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); @@ -82,66 +88,11 @@ public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) return byteArrayPointer; } - */ - - [UnmanagedCallersOnly(EntryPoint = "Fortunes")] - public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) - { - List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); - - int totalSize = 0; - - foreach (var fortune in fortunes) - { - totalSize += sizeof(int) // for Id - + Encoding.UTF8.GetByteCount(fortune.Message ?? "") // for Message - + _delimiter.Length; // for delimiter - } - - // Allocate the total buffer - byte[] buffer = new byte[totalSize]; - int offset = 0; - - // Write each object to the buffer - foreach (var fortune in fortunes) - { - // Write Id - BitConverter.TryWriteBytes(buffer.AsSpan(offset, sizeof(int)), fortune.Id); - offset += sizeof(int); - - // Write Message - int descriptionLength = Encoding.UTF8.GetBytes(fortune.Message ?? "", buffer.AsSpan(offset)); - offset += descriptionLength; - - // Write Delimiter - _delimiter.CopyTo(buffer, offset); - offset += _delimiter.Length; - } - - byte[] byteArray = buffer.ToArray(); - *length = byteArray.Length; - - /* - var memoryStream = new MemoryStream(); - using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); - - _fortunesSerializer.Serialize(utf8JsonWriter, fortunes); - - byte[] byteArray = memoryStream.ToArray(); - *length = (int)utf8JsonWriter.BytesCommitted; - */ - - GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); - IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); - *handlePointer = GCHandle.ToIntPtr(handle); - - return byteArrayPointer; - } [UnmanagedCallersOnly(EntryPoint = "Query")] public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointer) { - World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult(); + World[] worlds = RawDb.ReadMultipleRows(queries); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -161,7 +112,7 @@ public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointe [UnmanagedCallersOnly(EntryPoint = "Updates")] public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer) { - World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult(); + World[] worlds = RawDb.LoadMultipleUpdatesRows(count); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -181,7 +132,7 @@ public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointe [UnmanagedCallersOnly(EntryPoint = "DbById")] public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer) { - var world = RawDb.LoadSingleQueryRowById(id).GetAwaiter().GetResult(); + var world = RawDb.LoadSingleQueryRowById(id); var memoryStream = new MemoryStream(); using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); @@ -198,3 +149,5 @@ public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer) return byteArrayPointer; } } + +#endif \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs index c6eb823c9fa..599ec7425e9 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs @@ -1,3 +1,5 @@ +using System; + namespace appMpower.Orm.Objects { public readonly struct Fortune : IComparable, IComparable diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs index fec986f8755..91105a8ed7c 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs @@ -1,4 +1,7 @@ +using System; +using System.Collections.Generic; using System.Data; +using System.Threading.Tasks; using appMpower.Orm.Data; using appMpower.Orm.Objects; using PlatformBenchmarks; @@ -9,46 +12,81 @@ public static class RawDb { private const int MaxBatch = 500; +#if ADO + private static ConcurrentRandom _random = new ConcurrentRandom(); +#else private static Random _random = new Random(); +#endif private static string[] _queriesMultipleRows = new string[MaxBatch + 1]; - public static async Task LoadSingleQueryRow() +#if AOTDLL + public static World LoadSingleQueryRow() +#else + public static async Task LoadSingleQueryRowAsync() +#endif { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + using var pooledConnection = new DbConnection(DbFactory.ConnectionString); +#if AOTDLL + pooledConnection.Open(); +#else await pooledConnection.OpenAsync(); +#endif var (dbCommand, _) = CreateReadCommand(pooledConnection); using (dbCommand) { - World world = await ReadSingleRow(dbCommand); - +#if AOTDLL + World world = ReadSingleRow(dbCommand); +#else + World world = await ReadSingleRowAsync(dbCommand); +#endif return world; } } - public static async Task LoadSingleQueryRowById(int id) + +#if AOTDLL + public static World LoadSingleQueryRowById(int id) +#else + public static async Task LoadSingleQueryRowByIdAsync(int id) +#endif { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + using var pooledConnection = new DbConnection(DbFactory.ConnectionString); +#if AOTDLL + pooledConnection.Open(); +#else await pooledConnection.OpenAsync(); +#endif var (dbCommand, _) = CreateReadCommandById(pooledConnection, id); using (dbCommand) { - World world = await ReadSingleRow(dbCommand); - +#if AOTDLL + World world = ReadSingleRow(dbCommand); +#else + World world = await ReadSingleRowAsync(dbCommand); +#endif return world; } } - public static async Task LoadMultipleQueriesRows(int count) +#if AOTDLL + public static World[] LoadMultipleQueriesRows(int count) +#else + public static async Task LoadMultipleQueriesRowsAsync(int count) +#endif { var worlds = new World[count]; - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + using var pooledConnection = new DbConnection(DbFactory.ConnectionString); +#if AOTDLL + pooledConnection.Open(); +#else await pooledConnection.OpenAsync(); +#endif var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); @@ -56,7 +94,11 @@ public static async Task LoadMultipleQueriesRows(int count) { for (int i = 0; i < count; i++) { - worlds[i] = await ReadSingleRow(dbCommand); +#if AOTDLL + worlds[i] = ReadSingleRow(dbCommand); +#else + worlds[i] = await ReadSingleRowAsync(dbCommand); +#endif dbDataParameter.Value = _random.Next(1, 10001); } } @@ -64,45 +106,20 @@ public static async Task LoadMultipleQueriesRows(int count) return worlds; } - public static async Task> LoadFortunesRows() - { - var fortunes = new List(); - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection); - - using (dbCommand) - { - IDataReader dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); - - while (dataReader.Read()) - { - fortunes.Add(new Fortune - ( - id: dataReader.GetInt32(0), - //MariaDB ODBC connector does not correctly support Japanese characters in combination with default ADO.NET; - //as a solution we custom read this string - message: (Constants.Dbms == Dbms.MySQL ? ReadColumn(dataReader, 1) : dataReader.GetString(1)) - )); - } - - dataReader.Close(); - } - - fortunes.Add(new Fortune(id: 0, message: "Additional fortune added at request time.")); - fortunes.Sort(); - - return fortunes; - } - - public static async Task LoadMultipleUpdatesRows(int count) +#if AOTDLL + public static World[] LoadMultipleUpdatesRows(int count) +#else + public static async Task LoadMultipleUpdatesRowsAsync(int count) +#endif { var worlds = new World[count]; - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString, true); + using var pooledConnection = new DbConnection(DbFactory.ConnectionString, true); +#if AOTDLL + pooledConnection.Open(); +#else await pooledConnection.OpenAsync(); +#endif var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection); @@ -110,7 +127,12 @@ public static async Task LoadMultipleUpdatesRows(int count) { for (int i = 0; i < count; i++) { - worlds[i] = await ReadSingleRow(queryCommand); +#if AOTDLL + worlds[i] = ReadSingleRow(queryCommand); +#else + worlds[i] = await ReadSingleRowAsync(queryCommand); +#endif + dbDataParameter.Value = _random.Next(1, 10001); } } @@ -130,40 +152,124 @@ public static async Task LoadMultipleUpdatesRows(int count) worlds[i].RandomNumber = randomNumber; } - if (Constants.Dbms != Dbms.MySQL) +#if !MYSQL + var jds = BatchUpdateString.Jds; + + for (int i = 0; i < count; i++) { - var jds = BatchUpdateString.Jds; + updateCommand.CreateParameter(jds[i], DbType.Int32, worlds[i].Id); + } +#endif - for (int i = 0; i < count; i++) + updateCommand.ExecuteNonQuery(); + + return worlds; + } + +#if AOTDLL + public static List LoadFortunesRows() +#else + public static async Task> LoadFortunesRowsAsync() +#endif + { + var fortunes = new List(); + + using var pooledConnection = new DbConnection(DbFactory.ConnectionString); +#if AOTDLL + pooledConnection.Open(); +#else + await pooledConnection.OpenAsync(); +#endif + + var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection); + + using (dbCommand) + { +#if AOTDLL + var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); + while (dataReader.Read()) +#else + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); + while (await dataReader.ReadAsync()) +#endif { - updateCommand.CreateParameter(jds[i], DbType.Int32, worlds[i].Id); + fortunes.Add(new Fortune + ( + id: dataReader.GetInt32(0), + //MariaDB ODBC connector does not correctly support Japanese characters in combination with default ADO.NET; + //as a solution we custom read this string +#if ODBC && MYSQL + message: ReadColumn(dataReader, 1)) +#else + message: dataReader.GetString(1)) +#endif + ); } + + dataReader.Close(); } - updateCommand.ExecuteNonQuery(); + fortunes.Add(new Fortune(id: 0, message: "Additional fortune added at request time.")); + fortunes.Sort(); - return worlds; + return fortunes; } - internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection) +#if ODBC && MYSQL + public static string ReadColumn(IDataReader dataReader, int column) { - DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); + long size = dataReader.GetBytes(column, 0, null, 0, 0); //get the length of data + byte[] values = new byte[size]; + + int bufferSize = 64; + long bytesRead = 0; + int currentPosition = 0; + + while (bytesRead < size) + { + bytesRead += dataReader.GetBytes(column, currentPosition, values, currentPosition, bufferSize); + currentPosition += bufferSize; + } + + return System.Text.Encoding.Default.GetString(values); + } +#endif + + private static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection) + { +#if ADO + var dbCommand = new DbCommand("SELECT * FROM world WHERE id=@Id", pooledConnection); +#else + var dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); +#endif return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001))); } internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommandById(DbConnection pooledConnection, int id) { - DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); +#if ADO + var dbCommand = new DbCommand("SELECT * FROM world WHERE id=@Id", pooledConnection); +#else + var dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); +#endif return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id)); } - internal static async Task ReadSingleRow(DbCommand dbCommand) +#if AOTDLL + internal static World ReadSingleRow(DbCommand dbCommand) +#else + internal static async Task ReadSingleRowAsync(DbCommand dbCommand) +#endif { - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); - +#if AOTDLL + var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); dataReader.Read(); +#else + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); + await dataReader.ReadAsync(); +#endif var world = new World { @@ -176,7 +282,11 @@ internal static async Task ReadSingleRow(DbCommand dbCommand) return world; } - public static async Task ReadMultipleRows(int count) +#if AOTDLL + public static World[] ReadMultipleRows(int count) +#else + public static async Task ReadMultipleRowsAsync(int count) +#endif { int j = 0; var ids = BatchUpdateString.Ids; @@ -199,8 +309,12 @@ public static async Task ReadMultipleRows(int count) queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder); } - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + using var pooledConnection = new DbConnection(DbFactory.ConnectionString); +#if AOTDLL + pooledConnection.Open(); +#else await pooledConnection.OpenAsync(); +#endif using var dbCommand = new DbCommand(queryString, pooledConnection); @@ -209,11 +323,19 @@ public static async Task ReadMultipleRows(int count) dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001)); } - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess); +#if AOTDLL + var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); +#else + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); +#endif do { +#if AOTDLL dataReader.Read(); +#else + await dataReader.ReadAsync(); +#endif worlds[j] = new World { @@ -222,29 +344,16 @@ public static async Task ReadMultipleRows(int count) }; j++; - } while (await dataReader.NextResultAsync()); + } +#if AOTDLL + while (dataReader.NextResult()); +#else + while (await dataReader.NextResultAsync()); +#endif dataReader.Close(); return worlds; } - - public static string ReadColumn(IDataReader dataReader, int column) - { - long size = dataReader.GetBytes(column, 0, null, 0, 0); //get the length of data - byte[] values = new byte[size]; - - int bufferSize = 64; - long bytesRead = 0; - int currentPosition = 0; - - while (bytesRead < size) - { - bytesRead += dataReader.GetBytes(column, currentPosition, values, currentPosition, bufferSize); - currentPosition += bufferSize; - } - - return System.Text.Encoding.Default.GetString(values); - } } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/FortunesSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/FortunesSerializer.cs index d1697c0c0cc..1f5d30a7a45 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/FortunesSerializer.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/FortunesSerializer.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Text.Json; using appMpower.Orm.Objects; diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj index 19ac29572de..95b4eb56821 100644 --- a/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj @@ -1,47 +1,90 @@  + net10.0 - enable + true + + + false + + false + false + false + partial + + + true true - true - linux-x64 + true + full + + Size + Size + + false + false + false + false + false + false + true + true + + false false - Size - none - false + true - true - true - true - false + false - true + none + false - true + true - true + true + - true - false - false + + + $(NoWarn);IL2093 + + $(DefineConstants);AOTDLL + $(DefineConstants);ADO + $(DefineConstants);ODBC + $(DefineConstants);POSTGRESQL + $(DefineConstants);MYSQL + + - + + + + + + - + \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs index 93a91a7529a..38b5323c1d8 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs @@ -3,10 +3,13 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +#if !AOTDLL +using appMpower.Orm; +#endif + namespace appMpower; public class CachingMiddleware @@ -20,113 +23,110 @@ public class CachingMiddleware private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("application/json")); - - private readonly RequestDelegate _next; + new("Content-Type", new StringValues("application/json")); - public CachingMiddleware(RequestDelegate next) + public static async Task Invoke(HttpContext httpContext) { - _next = next; - } + byte[] json; - public unsafe Task Invoke(HttpContext httpContext) - { - if (httpContext.Request.Path.StartsWithSegments("/cached-worlds", StringComparison.Ordinal)) - { - int payloadLength; - IntPtr handlePointer; - IntPtr bytePointer; - byte[] json; +#if AOTDLL + int payloadLength; + IntPtr handlePointer; + IntPtr bytePointer; +#endif - if (_cache.Count == 0) + if (_cache.Count == 0) + { + for (int i = 1; i < 10001; i++) { - for (int i = 1; i < 10001; i++) - { - bytePointer = NativeMethods.DbById(i, out payloadLength, out handlePointer); - json = new byte[payloadLength]; - //Marshal.Copy(bytePointer, json, 0, payloadLength); - - fixed (byte* dest = json) - { - Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); - } +#if AOTDLL + bytePointer = NativeMethods.DbById(i, out payloadLength, out handlePointer); + json = new byte[payloadLength]; + //Marshal.Copy(bytePointer, json, 0, payloadLength); - NativeMethods.FreeHandlePointer(handlePointer); - _cache.Add(i, json); + unsafe + { + fixed (byte* dest = json) + { + Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); + } } + + NativeMethods.FreeHandlePointer(handlePointer); +#else + json = await DotnetMethods.DbById(i); +#endif + _cache.Add(i, json); } + } - var queryString = httpContext.Request.QueryString.ToString(); - int queries; - Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out queries); - queries = queries > 500 ? 500 : (queries > 0 ? queries : 1); + var queryString = httpContext.Request.QueryString.ToString(); + int queries; + Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out queries); + queries = queries > 500 ? 500 : (queries > 0 ? queries : 1); - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); - int queriesLength = 0; - int[] keys = new int[queries]; + int queriesLength = 0; + int[] keys = new int[queries]; - for (int i = 0; i < queries; i++) + for (int i = 0; i < queries; i++) + { + keys[i] = _random.Next(1, 10001); + + if (!_cache.TryGetValue(keys[i], out json)) { - keys[i] = _random.Next(1, 10001); - - if (!_cache.TryGetValue(keys[i], out json)) - { - bytePointer = NativeMethods.DbById(keys[i], out payloadLength, out handlePointer); - json = new byte[payloadLength]; - //Marshal.Copy(bytePointer, json, 0, payloadLength); - - fixed (byte* dest = json) - { - Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); - } +#if AOTDLL + bytePointer = NativeMethods.DbById(keys[i], out payloadLength, out handlePointer); + json = new byte[payloadLength]; + //Marshal.Copy(bytePointer, json, 0, payloadLength); - NativeMethods.FreeHandlePointer(handlePointer); - _cache.Add(keys[i], json); + unsafe + { + fixed (byte* dest = json) + { + Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); + } } - queriesLength += json.Length; + NativeMethods.FreeHandlePointer(handlePointer); +#else + json = await DotnetMethods.DbById(keys[i]); +#endif + _cache.Add(keys[i], json); } - byte[] result = new byte[_startBytes.Length + _endBytes.Length + (_comma.Length * queries - 1) + queriesLength]; - int position = 0; - - Buffer.BlockCopy(_startBytes, 0, result, position, _startBytes.Length); - position += _startBytes.Length; - - for (int i = 0; i < queries; i++) - { - json = _cache[keys[i]]; - Buffer.BlockCopy(json, 0, result, position, json.Length); - position += json.Length; + queriesLength += json.Length; + } - if (i < queries - 1) - { - Buffer.BlockCopy(_comma, 0, result, position, _comma.Length); - position += _comma.Length; - } - } + byte[] result = new byte[_startBytes.Length + _endBytes.Length + (_comma.Length * queries - 1) + queriesLength]; + int position = 0; - Buffer.BlockCopy(_endBytes, 0, result, position, _endBytes.Length); + Buffer.BlockCopy(_startBytes, 0, result, position, _startBytes.Length); + position += _startBytes.Length; - response.Headers.Add( - new KeyValuePair("Content-Length", result.Length.ToString())); + for (int i = 0; i < queries; i++) + { + json = _cache[keys[i]]; + Buffer.BlockCopy(json, 0, result, position, json.Length); + position += json.Length; - return response.Body.WriteAsync(result, 0, result.Length); + if (i < queries - 1) + { + Buffer.BlockCopy(_comma, 0, result, position, _comma.Length); + position += _comma.Length; + } } - return _next(httpContext); - } -} + Buffer.BlockCopy(_endBytes, 0, result, position, _endBytes.Length); -public static class CachingMiddlewareExtensions -{ - public static IApplicationBuilder UseCaching(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); + response.Headers.Add( + new KeyValuePair("Content-Length", result.Length.ToString())); + + await response.Body.WriteAsync(result); } -} +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs index 6e16aaec5fb..957f279a372 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs @@ -1,178 +1,56 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Text; using System.Text.Encodings.Web; -using System.Text.Json; using System.Text.Unicode; using System.Threading.Tasks; -using appMpower.Objects; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +#if !AOTDLL +using appMpower.Orm; +#endif + namespace appMpower; public class FortunesMiddleware { - static readonly HtmlEncoder htmlEncoder = CreateHtmlEncoder(); - static HtmlEncoder CreateHtmlEncoder() - { - var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana); - settings.AllowCharacter('\u2014'); // allow EM DASH through - return HtmlEncoder.Create(settings); - } - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("text/html; charset=UTF-8")); + new("Content-Type", new StringValues("text/html; charset=UTF-8")); - private static readonly byte[] _delimiter = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }; - - private readonly RequestDelegate _next; - - public FortunesMiddleware(RequestDelegate next) - { - _next = next; - } + private static readonly byte[] _delimiter = [0xFF, 0xFF, 0xFF, 0xFF]; - public unsafe Task Invoke(HttpContext httpContext) + public static async Task Invoke(HttpContext httpContext) { - if (httpContext.Request.Path.StartsWithSegments("/fortunes", StringComparison.Ordinal)) - { - int payloadLength; - IntPtr handlePointer; - - IntPtr bytePointer = NativeMethods.Fortunes(out payloadLength, out handlePointer); - - /* - byte[] json = new byte[payloadLength]; - Marshal.Copy(bytePointer, json, 0, payloadLength); - NativeMethods.FreeHandlePointer(handlePointer); - - string s = Encoding.UTF8.GetString(json, 0, json.Length); - - var options = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }; + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); - List fortunes = JsonSerializer.Deserialize>(s, options); - - var response = httpContext.Response; - response.Headers.Add(_headerServer); - - var result = Results.Extensions.RazorSlice>(fortunes); - result.HtmlEncoder = htmlEncoder; - - return result.ExecuteAsync(httpContext); - */ - - byte[] byteArray = new byte[payloadLength]; - //Marshal.Copy(bytePointer, json, 0, payloadLength); - - fixed (byte* dest = byteArray) - { - Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); - } - - List fortunes = new List(); - - // Convert the byte array into segments split by the delimiter - int delimiterLength = _delimiter.Length; - int start = 0; - int index; - - while ((index = FindDelimiterIndex(byteArray, _delimiter, start)) >= 0) - { - // Use a span over the segment of bytes for the current object - var objectDataSpan = new ReadOnlySpan(byteArray, start, index - start); - Fortune fortune = ConvertBytesToObject(objectDataSpan); - fortunes.Add(fortune); - - // Move past the delimiter - start = index + delimiterLength; - } +#if AOTDLL + int payloadLength; + IntPtr handlePointer; - NativeMethods.FreeHandlePointer(handlePointer); + IntPtr bytePointer = NativeMethods.Fortunes(out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + //Marshal.Copy(bytePointer, json, 0, payloadLength); - var response = httpContext.Response; - response.Headers.Add(_headerServer); - - var result = Results.Extensions.RazorSlice>(fortunes); - result.HtmlEncoder = htmlEncoder; - - return result.ExecuteAsync(httpContext); - - /* - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); - - int payloadLength; - IntPtr handlePointer; - - IntPtr bytePointer = NativeMethods.Fortunes(out payloadLength, out handlePointer); - byte[] json = new byte[payloadLength]; - Marshal.Copy(bytePointer, json, 0, payloadLength); - NativeMethods.FreeHandlePointer(handlePointer); - - response.Headers.Add( - new KeyValuePair("Content-Length", payloadLength.ToString())); - - return response.Body.WriteAsync(json, 0, payloadLength); - */ - } - - return _next(httpContext); - } - - private static int FindDelimiterIndex(byte[] array, byte[] delimiter, int startIndex) - { - int endIndex = array.Length - delimiter.Length; - - for (int i = startIndex; i <= endIndex; i++) + unsafe { - bool isMatch = true; - - for (int j = 0; j < delimiter.Length; j++) + fixed (byte* dest = json) { - if (array[i + j] != delimiter[j]) - { - isMatch = false; - break; - } - } - - if (isMatch) - { - return i; + Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); } } - return -1; - } - - private static Fortune ConvertBytesToObject(ReadOnlySpan data) - { - int offset = 0; + NativeMethods.FreeHandlePointer(handlePointer); +#else + byte[] json = await DotnetMethods.Fortunes(); +#endif + response.Headers.Add( + new KeyValuePair("Content-Length", json.Length.ToString())); - // Read Id - int id = BitConverter.ToInt32(data.Slice(offset, sizeof(int))); - offset += sizeof(int); - - // Read Message (remaining bytes in the span) - string message = Encoding.UTF8.GetString(data.Slice(offset)); - - return new Fortune(id, message); - } -} - -public static class FortunesMiddlewareExtensions -{ - public static IApplicationBuilder UseFortunes(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); + await response.Body.WriteAsync(json); } -} +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs index 2e90051ff2f..d9cd8a6557e 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs @@ -1,8 +1,6 @@ -using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using appMpower.Serializers; @@ -20,45 +18,25 @@ public class JsonMiddleware private readonly static JsonMessageSerializer _jsonMessageSerializer = new JsonMessageSerializer(); private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("application/json")); + new("Content-Type", new StringValues("application/json")); - private readonly RequestDelegate _nextStage; - - public JsonMiddleware(RequestDelegate nextStage) + public static Task Invoke(HttpContext httpContext) { - _nextStage = nextStage; - } - - public unsafe Task Invoke(HttpContext httpContext) - { - if (httpContext.Request.Path.StartsWithSegments("/json", StringComparison.Ordinal)) - { - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); - - using var utf8JsonWriter = new Utf8JsonWriter(httpContext.Response.Body, _jsonWriterOptions); + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); - _jsonMessageSerializer.Serialize(utf8JsonWriter, new JsonMessage { Message = "Hello, World!" }); + using var utf8JsonWriter = new Utf8JsonWriter(httpContext.Response.Body, _jsonWriterOptions); - response.Headers.Add( - new KeyValuePair("Content-Length", utf8JsonWriter.BytesPending.ToString())); + _jsonMessageSerializer.Serialize(utf8JsonWriter, new JsonMessage { Message = "Hello, World!" }); - utf8JsonWriter.Flush(); + response.Headers.Add( + new KeyValuePair("Content-Length", utf8JsonWriter.BytesPending.ToString())); - return Task.CompletedTask; - } + utf8JsonWriter.Flush(); - return _nextStage(httpContext); - } -} - -public static class JsonMiddlewareExtensions -{ - public static IApplicationBuilder UseJson(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); + return Task.CompletedTask; } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs index f2e6829f79c..c6f0eabfc04 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs @@ -2,67 +2,56 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -namespace appMpower; +#if !AOTDLL +using appMpower.Orm; +#endif + +namespace appMpower; public class MultipleQueriesMiddleware { private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("application/json")); - - private readonly RequestDelegate _next; - - public MultipleQueriesMiddleware(RequestDelegate next) - { - _next = next; - } - - public unsafe Task Invoke(HttpContext httpContext) - { - if (httpContext.Request.Path.StartsWithSegments("/queries", StringComparison.Ordinal)) - { - var queryString = httpContext.Request.QueryString.ToString(); - int queries; - Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out queries); - queries = queries > 500 ? 500 : (queries > 0 ? queries : 1); - - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); - - int payloadLength; - IntPtr handlePointer; - - IntPtr bytePointer = NativeMethods.Query(queries, out payloadLength, out handlePointer); - byte[] json = new byte[payloadLength]; - //Marshal.Copy(bytePointer, json, 0, payloadLength); - - fixed (byte* dest = json) - { - Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); - } - - NativeMethods.FreeHandlePointer(handlePointer); - - response.Headers.Add( - new KeyValuePair("Content-Length", payloadLength.ToString())); - - return response.Body.WriteAsync(json, 0, payloadLength); - } - - return _next(httpContext); - } -} - -public static class MultipleQueriesMiddlewareExtensions -{ - public static IApplicationBuilder UseMultipleQueries(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } -} + new("Content-Type", new StringValues("application/json")); + + public static async Task Invoke(HttpContext httpContext) + { + var queryString = httpContext.Request.QueryString.ToString(); + int queries; + Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out queries); + queries = queries > 500 ? 500 : (queries > 0 ? queries : 1); + + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + +#if AOTDLL + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Query(queries, out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + //Marshal.Copy(bytePointer, json, 0, payloadLength); + + unsafe + { + fixed (byte* dest = json) + { + Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); + } + } + + NativeMethods.FreeHandlePointer(handlePointer); +#else + byte[] json = await DotnetMethods.Query(queries); +#endif + response.Headers.Add( + new KeyValuePair("Content-Length", json.Length.ToString())); + + await response.Body.WriteAsync(json); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs index 672f0d14e0f..5a38a13f0ae 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs @@ -2,67 +2,57 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +#if !AOTDLL +using appMpower.Orm; +#endif + namespace appMpower; public class MultipleUpdatesMiddelware { private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("application/json")); - - private readonly RequestDelegate _next; + new("Content-Type", new StringValues("application/json")); - public MultipleUpdatesMiddelware(RequestDelegate next) + public static async Task Invoke(HttpContext httpContext) { - _next = next; - } + var queryString = httpContext.Request.QueryString.ToString(); + int count; + Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out count); + count = count > 500 ? 500 : (count > 0 ? count : 1); - public unsafe Task Invoke(HttpContext httpContext) - { - if (httpContext.Request.Path.StartsWithSegments("/updates", StringComparison.Ordinal)) - { - var queryString = httpContext.Request.QueryString.ToString(); - int count; - Int32.TryParse(queryString.Substring(queryString.LastIndexOf("=") + 1), out count); - count = count > 500 ? 500 : (count > 0 ? count : 1); - - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); - int payloadLength; - IntPtr handlePointer; +#if AOTDLL + int payloadLength; + IntPtr handlePointer; - IntPtr bytePointer = NativeMethods.Updates(count, out payloadLength, out handlePointer); - byte[] json = new byte[payloadLength]; - //Marshal.Copy(bytePointer, json, 0, payloadLength); + IntPtr bytePointer = NativeMethods.Updates(count, out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + //Marshal.Copy(bytePointer, json, 0, payloadLength); + unsafe + { fixed (byte* dest = json) { Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); } - - NativeMethods.FreeHandlePointer(handlePointer); - - response.Headers.Add( - new KeyValuePair("Content-Length", payloadLength.ToString())); - - return response.Body.WriteAsync(json, 0, payloadLength); } - return _next(httpContext); - } -} + NativeMethods.FreeHandlePointer(handlePointer); +#else + byte[] json = await DotnetMethods.Updates(count); +#endif -public static class MultipleUpdatesMiddelwareExtensions -{ - public static IApplicationBuilder UseMultipleUpdates(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); + response.Headers.Add( + new KeyValuePair("Content-Length", json.Length.ToString())); + + await response.Body.WriteAsync(json); } -} +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs index cf7ad20e54a..489289c02da 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs @@ -1,50 +1,28 @@ -using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; namespace appMpower; -public unsafe class PlaintextMiddleware +public class PlaintextMiddleware { private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("text/plain")); + new("Content-Type", new StringValues("text/plain")); private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); - private readonly RequestDelegate _nextStage; - - public PlaintextMiddleware(RequestDelegate nextStage) - { - _nextStage = nextStage; - } - - public Task Invoke(HttpContext httpContext) - { - if (httpContext.Request.Path.StartsWithSegments("/plaintext", StringComparison.Ordinal)) - { - var payloadLength = _helloWorldPayload.Length; - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); - response.Headers.Add( - new KeyValuePair("Content-Length", payloadLength.ToString())); - - return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength); - } - - return _nextStage(httpContext); - } -} - -public static class PlaintextMiddlewareExtensions -{ - public static IApplicationBuilder UsePlainText(this IApplicationBuilder builder) + public static async Task Invoke(HttpContext httpContext) { - return builder.UseMiddleware(); + var payloadLength = _helloWorldPayload.Length; + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + response.Headers.Add( + new KeyValuePair("Content-Length", payloadLength.ToString())); + + await response.Body.WriteAsync(_helloWorldPayload); } -} +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs index 747a55c5a63..ccf62d05397 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; +using System.Text.Json; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; +using appMpower.Orm; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; @@ -11,53 +11,40 @@ namespace appMpower; public class SingleQueryMiddleware { private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); + new("Server", new StringValues("k")); private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("application/json")); + new("Content-Type", new StringValues("application/json")); - private readonly RequestDelegate _nextStage; - - public SingleQueryMiddleware(RequestDelegate nextStage) + public static async Task Invoke(HttpContext httpContext) { - _nextStage = nextStage; - } + var response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); - public unsafe Task Invoke(HttpContext httpContext) - { - if (httpContext.Request.Path.StartsWithSegments("/db", StringComparison.Ordinal)) - { - var response = httpContext.Response; - response.Headers.Add(_headerServer); - response.Headers.Add(_headerContentType); +#if AOTDLL + int payloadLength; + IntPtr handlePointer; - int payloadLength; - IntPtr handlePointer; - - IntPtr bytePointer = NativeMethods.Db(out payloadLength, out handlePointer); - byte[] json = new byte[payloadLength]; - //Marshal.Copy(bytePointer, json, 0, payloadLength); + IntPtr bytePointer = NativeMethods.Db(out payloadLength, out handlePointer); + byte[] json = new byte[payloadLength]; + //Marshal.Copy(bytePointer, json, 0, payloadLength); + unsafe + { fixed (byte* dest = json) { Buffer.MemoryCopy((void*)bytePointer, dest, payloadLength, payloadLength); } - - NativeMethods.FreeHandlePointer(handlePointer); - - response.Headers.Add( - new KeyValuePair("Content-Length", payloadLength.ToString())); - - return response.Body.WriteAsync(json, 0, payloadLength); } - return _nextStage(httpContext); - } -} + NativeMethods.FreeHandlePointer(handlePointer); +#else + byte[] json = await DotnetMethods.Db(); +#endif -public static class SingleQueryMiddlewareExtensions -{ - public static IApplicationBuilder UseSingleQuery(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); + response.Headers.Add( + new KeyValuePair("Content-Length", json.Length.ToString())); + + await response.Body.WriteAsync(json); } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs index 89b8a0764e3..1b2d179dc6f 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs @@ -1,3 +1,4 @@ +#if AOTDLL using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -28,7 +29,6 @@ public static partial class NativeMethods [LibraryImport(LibName, EntryPoint = "Fortunes", StringMarshalling = StringMarshalling.Utf16)] [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial IntPtr Fortunes(out int length, out IntPtr handlePointer); [LibraryImport(LibName, EntryPoint = "Query", StringMarshalling = StringMarshalling.Utf16)] @@ -43,4 +43,5 @@ public static partial class NativeMethods [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] public static partial IntPtr DbById(int id, out int length, out IntPtr handlePointer); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Program.cs b/frameworks/CSharp/appmpower/src/appMpower/Program.cs index f2f36aa627d..88b9c37fe04 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Program.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Program.cs @@ -1,44 +1,122 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; - -namespace appMpower; - -class Program -{ - static void Main(string[] args) - { - BuildWebHost(args).Run(); - } - - static IHost BuildWebHost(string[] args) - { - var config = new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .AddEnvironmentVariables(prefix: "ASPNETCORE_") - .AddCommandLine(args) - .Build(); - - var appSettings = config.GetSection("AppSettings").Get(); - - var host = Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseConfiguration(config) - .UseKestrel(options => - { - options.AddServerHeader = false; - options.AllowSynchronousIO = true; - }) - .UseStartup(); - }) - .Build(); - - return host; - } -} - -public class AppSettings -{ - public string Database { get; set; } -} +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; + +#if !AOTDLL +using appMpower.Orm; +#endif + +namespace appMpower; + +class Program +{ + static void Main(string[] args) + { + // ------------------------------------------------------------ + // 1) Load configuration files (independent of ASP.NET host) + // ------------------------------------------------------------ + IConfigurationRoot fileConfig = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .Build(); + + // Use config values as defaults when env vars not provided + ApplyDatabaseDefaults(fileConfig); + + // ------------------------------------------------------------ + // 2) Create builder + // ------------------------------------------------------------ + var builder = WebApplication.CreateSlimBuilder(args); + + // Hardening: prevent external hosting startup + built-in startup filters + builder.WebHost.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true"); + builder.Services.RemoveAll(); + + // Logging (keep simple) + builder.Logging.ClearProviders(); + //builder.Logging.AddConsole(); + + // ------------------------------------------------------------ + // 3) Compose builder.Configuration (merge file config + env + CLI) + // ------------------------------------------------------------ + builder.Configuration.AddConfiguration(fileConfig); + builder.Configuration.AddEnvironmentVariables(prefix: "ASPNETCORE_"); + builder.Configuration.AddCommandLine(args); + + builder.WebHost.ConfigureKestrel(options => + { + options.AddServerHeader = false; + options.AllowSynchronousIO = true; + }); + + var startup = new Startup(); + startup.ConfigureServices(builder.Services, builder.Configuration); + + // ------------------------------------------------------------ + // 4) Build + // ------------------------------------------------------------ + var app = builder.Build(); + + // ------------------------------------------------------------ + // 5) Pipeline + // ------------------------------------------------------------ + + // Your existing Startup pipeline + startup.Configure(app); + + // ------------------------------------------------------------ + // 6) Log addresses after startup + // ------------------------------------------------------------ + app.Lifetime.ApplicationStarted.Register(() => + { + var addresses = app.Services + .GetRequiredService() + .Features + .Get(); + + if (addresses is not null) + { + foreach (var address in addresses.Addresses) + Console.WriteLine($"🚀 Listening on {address}"); + } + }); + + // ------------------------------------------------------------ + // 7) Run + // ------------------------------------------------------------ + app.Run(); + } + + private static void ApplyDatabaseDefaults(IConfiguration config) + { +#if AOTDLL + #if ODBC + NativeMethods.DbProvider(1); //ODBC + #else + NativeMethods.DbProvider(0); //ADO + #endif + + #if POSTGRESQL + NativeMethods.Dbms(1); //PostgreSQL + #else + NativeMethods.Dbms(0); //MySQL + #endif +#else + #if ODBC + DotnetMethods.DbProvider(1); //ODBC + #else + DotnetMethods.DbProvider(0); //ADO + #endif + + #if POSTGRESQL + DotnetMethods.Dbms(1); //PostgreSQL + #else + DotnetMethods.Dbms(0); //MySQL + #endif +#endif + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Slices/Fortunes.cshtml b/frameworks/CSharp/appmpower/src/appMpower/Slices/Fortunes.cshtml deleted file mode 100644 index ebf2c38d5ec..00000000000 --- a/frameworks/CSharp/appmpower/src/appMpower/Slices/Fortunes.cshtml +++ /dev/null @@ -1,2 +0,0 @@ -@inherits RazorSliceHttpResult> -Fortunes@foreach (var item in Model){}
idmessage
@WriteNumber(item.Id, default, CultureInfo.InvariantCulture, false)@item.Message
\ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Slices/_ViewImports.cshtml b/frameworks/CSharp/appmpower/src/appMpower/Slices/_ViewImports.cshtml deleted file mode 100644 index 98a692ef65a..00000000000 --- a/frameworks/CSharp/appmpower/src/appMpower/Slices/_ViewImports.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@inherits RazorSliceHttpResult - -@using System.Globalization; -@using Microsoft.AspNetCore.Razor; -@using Microsoft.AspNetCore.Http.HttpResults; -@using RazorSlices; -@using appMpower.Objects; - -@tagHelperPrefix __disable_tagHelpers__: -@removeTagHelper *, Microsoft.AspNetCore.Mvc.Razor \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Startup.cs b/frameworks/CSharp/appmpower/src/appMpower/Startup.cs index 4b571cf8286..d7364c07468 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/Startup.cs +++ b/frameworks/CSharp/appmpower/src/appMpower/Startup.cs @@ -1,39 +1,17 @@ +using System; using System.Text.Encodings.Web; using System.Text.Unicode; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace appMpower; +namespace appMpower; -public class Startup +public sealed class Startup { - private readonly IConfiguration _configuration; - - public Startup(IConfiguration configuration) + public void ConfigureServices(IServiceCollection services, IConfiguration config) { - _configuration = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - var appSettings = _configuration.Get(); - services.AddSingleton(appSettings); - -#if !DEBUG - #if ODBC - NativeMethods.DbProvider(1); //ODBC - #else - NativeMethods.DbProvider(0); //ADO - #endif - - #if POSTGRESQL - NativeMethods.Dbms(1); //PostgreSQL - #else - NativeMethods.Dbms(0); //MySQL - #endif -#endif - var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana); settings.AllowCharacter('—'); @@ -43,14 +21,68 @@ public void ConfigureServices(IServiceCollection services) }); } - public void Configure(IApplicationBuilder app) + public void Configure(WebApplication app) { - app.UsePlainText(); - app.UseJson(); - app.UseSingleQuery(); - app.UseCaching(); - app.UseFortunes(); - app.UseMultipleQueries(); - app.UseMultipleUpdates(); + app.Use(async (httpContext, next) => + { + // ---------- PLAINTEXT ---------- + if (httpContext.Request.Path.StartsWithSegments("/plaintext", StringComparison.Ordinal)) + { + await PlaintextMiddleware.Invoke(httpContext); + return; + } + + // ---------- JSON ---------- + if (httpContext.Request.Path.StartsWithSegments("/json", StringComparison.Ordinal)) + { + await JsonMiddleware.Invoke(httpContext); + return; + } + + // ---------- SINGLE QUERY ---------- + if (httpContext.Request.Path.StartsWithSegments("/db", StringComparison.Ordinal)) + { + await SingleQueryMiddleware.Invoke(httpContext); + return; + } + + // ---------- CACHING ---------- + if (httpContext.Request.Path.StartsWithSegments("/cached-worlds", StringComparison.Ordinal)) + { + await CachingMiddleware.Invoke(httpContext); + return; + } + + // ---------- FORTUNES ---------- + if (httpContext.Request.Path.StartsWithSegments("/fortunes", StringComparison.Ordinal)) + { + await FortunesMiddleware.Invoke(httpContext); + return; + } + + // ---------- MULTIPLE QUERIES ---------- + if (httpContext.Request.Path.StartsWithSegments("/queries", StringComparison.Ordinal)) + { + await MultipleQueriesMiddleware.Invoke(httpContext); + return; + } + + // ---------- MULTIPLE UPDATES ---------- + if (httpContext.Request.Path.StartsWithSegments("/updates", StringComparison.Ordinal)) + { + await MultipleUpdatesMiddelware.Invoke(httpContext); + return; + } + + // If not handled here, let the rest of the pipeline run (404/endpoints/etc) + await next(); + }); + + // Optional: fallthrough response if nothing else handles it + app.Run(ctx => + { + ctx.Response.StatusCode = StatusCodes.Status404NotFound; + return ctx.Response.WriteAsync("Not found"); + }); } } \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj index dbb2d8436c4..b9e5c638089 100644 --- a/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj +++ b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj @@ -1,11 +1,63 @@ + net10.0 Exe true + + + false + + false + false + false + partial + + + + + true + true + + + linux-x64 + + + + + true + full + + Size + Size + + false + false + false + false + false + false + + true + true + + false + false + true + false + + none + false + true + + true + + + + @@ -22,15 +74,17 @@ --> - - - - - + $(DefineConstants);AOTEXE + $(DefineConstants);AOTDLL + $(DefineConstants);ADO $(DefineConstants);ODBC $(DefineConstants);POSTGRESQL $(DefineConstants);MYSQL + + + + \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/rd.xml b/frameworks/CSharp/appmpower/src/appMpower/rd.xml new file mode 100644 index 00000000000..8696730a4b4 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/rd.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frameworks/CSharp/aspnetcore/benchmark_config.json b/frameworks/CSharp/aspnetcore/benchmark_config.json index eb56fddfb57..2af76b0809f 100644 --- a/frameworks/CSharp/aspnetcore/benchmark_config.json +++ b/frameworks/CSharp/aspnetcore/benchmark_config.json @@ -12,7 +12,7 @@ "update_url": "/updates/", "cached_query_url": "/cached-worlds/", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "ASP.NET Core [Platform]", @@ -35,7 +35,7 @@ "update_url": "/updates/", "cached_query_url": "/cached-worlds/", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "ASP.NET Core [Platform]", @@ -101,7 +101,7 @@ "update_url": "/updates/", "cached_query_url": "/cached-worlds/", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "MySQL", "framework": "ASP.NET Core [Platform]", diff --git a/frameworks/CSharp/beetlex/benchmark_config.json b/frameworks/CSharp/beetlex/benchmark_config.json index 67f3a560196..794c24f7f53 100644 --- a/frameworks/CSharp/beetlex/benchmark_config.json +++ b/frameworks/CSharp/beetlex/benchmark_config.json @@ -34,7 +34,7 @@ "update_url": "/updates?queries=", "cached_query_url": "/cached-worlds?queries=", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "beetlex", diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/easyrpc/Benchmarks/Benchmarks.csproj deleted file mode 100644 index 33d112263f7..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Benchmarks.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - net5.0 - true - - - - - - - - - diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/AppSettings.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/AppSettings.cs deleted file mode 100644 index 8e7cabb74f0..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/AppSettings.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Benchmarks -{ - public class AppSettings - { - public string ConnectionString { get; set; } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/BatchUpdateString.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/BatchUpdateString.cs deleted file mode 100644 index b6b8c24965f..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/BatchUpdateString.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; - -namespace Benchmarks.Data -{ - internal class BatchUpdateString - { - private const int MaxBatch = 500; - - internal static readonly string[] Ids = Enumerable.Range(0, MaxBatch).Select(i => $"@Id_{i}").ToArray(); - internal static readonly string[] Randoms = Enumerable.Range(0, MaxBatch).Select(i => $"@Random_{i}").ToArray(); - - private static string[] _queries = new string[MaxBatch + 1]; - - public static string Query(int batchSize) - { - if (_queries[batchSize] != null) - { - return _queries[batchSize]; - } - - var lastIndex = batchSize - 1; - - var sb = StringBuilderCache.Acquire(); - - sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES "); - Enumerable.Range(0, lastIndex).ToList().ForEach(i => sb.Append($"(@Id_{i}, @Random_{i}), ")); - sb.Append($"(@Id_{lastIndex}, @Random_{lastIndex}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); - - return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/CachedWorld.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/CachedWorld.cs deleted file mode 100644 index a79f30e356a..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/CachedWorld.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Runtime.InteropServices; - -namespace Benchmarks.Data -{ - public class CachedWorld - { - public int id { get; set; } - - public int randomNumber { get; set; } - - public static implicit operator World(CachedWorld world) => new World { id = world.id, randomNumber = world.randomNumber }; - public static implicit operator CachedWorld(World world) => new CachedWorld { id = world.id, randomNumber = world.randomNumber }; - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/Fortune.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/Fortune.cs deleted file mode 100644 index b5cd9a5233e..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/Fortune.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Benchmarks.Data -{ - public readonly struct Fortune : IComparable, IComparable - { - public Fortune(int id, string message) - { - Id = id; - Message = message; - } - - public int Id { get; } - - public string Message { get; } - - public int CompareTo(object obj) => throw new InvalidOperationException("The non-generic CompareTo should not be used"); - - // Performance critical, using culture insensitive comparison - public int CompareTo(Fortune other) => string.CompareOrdinal(Message, other.Message); - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/Random.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/Random.cs deleted file mode 100644 index 5c86b5c2cb9..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/Random.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Runtime.CompilerServices; -using System.Threading; - -namespace Benchmarks.Data -{ - public class ConcurrentRandom - { - private static int nextSeed = 0; - - // Random isn't thread safe - [ThreadStatic] - private static Random _random; - - private static Random Random => _random ?? CreateRandom(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private static Random CreateRandom() - { - _random = new Random(Interlocked.Increment(ref nextSeed)); - return _random; - } - - public int Next(int minValue, int maxValue) - { - return Random.Next(minValue, maxValue); - } - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/RawDb.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/RawDb.cs deleted file mode 100644 index 56bc33c7a46..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/RawDb.cs +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.Extensions.Caching.Memory; -using Npgsql; - -namespace Benchmarks.Data -{ - public interface IRawDb - { - Task LoadSingleQueryRow(); - - Task LoadMultipleQueriesRows(int count); - - Task LoadMultipleUpdatesRows(int count); - - Task LoadCachedQueries(int count); - - Task> LoadFortunesRows(); - } - - - public class RawDb : IRawDb - { - private readonly string _connectionString; - private readonly MemoryCache _cache; - - public RawDb(AppSettings appSettings) - { - _connectionString = appSettings.ConnectionString; - - _cache = new MemoryCache( - new MemoryCacheOptions() - { - ExpirationScanFrequency = TimeSpan.FromMinutes(60) - }); - } - - public async Task LoadSingleQueryRow() - { - using (var db = new NpgsqlConnection(_connectionString)) - { - await db.OpenAsync(); - - var (cmd, _) = CreateReadCommand(db, new ConcurrentRandom()); - - using (cmd) - { - return await ReadSingleRow(cmd); - } - } - } - - public async Task> LoadFortunesRows() - { - var result = new List(); - - using (var db = new NpgsqlConnection(_connectionString)) - using (var cmd = db.CreateCommand()) - { - cmd.CommandText = "SELECT id, message FROM fortune"; - - await db.OpenAsync(); - - using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection)) - { - while (await rdr.ReadAsync()) - { - result.Add(new Fortune(rdr.GetInt32(0), rdr.GetString(1))); - } - } - } - - result.Add(new Fortune (0, "Additional fortune added at request time." )); - result.Sort(); - - return result; - } - - public async Task LoadMultipleQueriesRows(int count) - { - var random = new ConcurrentRandom(); - var result = new World[count]; - - using (var db = new NpgsqlConnection(_connectionString)) - { - await db.OpenAsync(); - - var (cmd, parameter) = CreateReadCommand(db, random); - - using (cmd) - { - for (int i = 0; i < count; i++) - { - result[i] = await ReadSingleRow(cmd); - - parameter.Value = random.Next(1, 10001); - } - } - } - - return result; - } - - public async Task LoadMultipleUpdatesRows(int count) - { - var random = new ConcurrentRandom(); - var results = new World[count]; - - using (var db = new NpgsqlConnection(_connectionString)) - { - await db.OpenAsync(); - - var (queryCmd, queryParameter) = CreateReadCommand(db, random); - - using (queryCmd) - { - for (int i = 0; i < results.Length; i++) - { - results[i] = await ReadSingleRow(queryCmd); - queryParameter.TypedValue = random.Next(1, 10001); - } - } - - using (var updateCmd = new NpgsqlCommand(BatchUpdateString.Query(count), db)) - { - var ids = BatchUpdateString.Ids; - var randoms = BatchUpdateString.Randoms; - - for (int i = 0; i < results.Length; i++) - { - var randomNumber = random.Next(1, 10001); - - updateCmd.Parameters.Add(new NpgsqlParameter(parameterName: ids[i], value: results[i].id)); - updateCmd.Parameters.Add(new NpgsqlParameter(parameterName: randoms[i], value: randomNumber)); - - results[i].randomNumber = randomNumber; - } - - await updateCmd.ExecuteNonQueryAsync(); - } - } - - return results; - } - - public Task LoadCachedQueries(int count) - { - var result = new World[count]; - var cacheKeys = _cacheKeys; - var cache = _cache; - var random = new ConcurrentRandom(); - - for (var i = 0; i < result.Length; i++) - { - var id = random.Next(1, 10001); - var key = cacheKeys[id]; - var data = cache.Get(key); - - if (data != null) - { - result[i] = data; - } - else - { - return LoadUncachedQueries(random, id, i, count, this, result); - } - } - - return Task.FromResult(result); - - static async Task LoadUncachedQueries(ConcurrentRandom random, int id, int i, int count, RawDb rawdb, World[] result) - { - using (var db = new NpgsqlConnection(rawdb._connectionString)) - { - await db.OpenAsync(); - - var (cmd, idParameter) = rawdb.CreateReadCommand(db,random); - - using (cmd) - { - Func> create = async (entry) => - { - return await rawdb.ReadSingleRow(cmd); - }; - - var cacheKeys = _cacheKeys; - var key = cacheKeys[id]; - - idParameter.TypedValue = id; - - for (; i < result.Length; i++) - { - var data = await rawdb._cache.GetOrCreateAsync(key, create); - result[i] = data; - - id = random.Next(1, 10001); - idParameter.TypedValue = id; - key = cacheKeys[id]; - } - } - } - - return result; - } - } - - private (NpgsqlCommand readCmd, NpgsqlParameter idParameter) CreateReadCommand(NpgsqlConnection connection, ConcurrentRandom random) - { - var cmd = new NpgsqlCommand("SELECT id, randomnumber FROM world WHERE id = @Id", connection); - - var parameter = new NpgsqlParameter(parameterName: "@Id", value: random.Next(1, 10001)); - - cmd.Parameters.Add(parameter); - - return (cmd, parameter); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private async Task ReadSingleRow(NpgsqlCommand cmd) - { - using (var rdr = await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.SingleRow)) - { - await rdr.ReadAsync(); - - return new World - { - id = rdr.GetInt32(0), - randomNumber = rdr.GetInt32(1) - }; - } - } - - private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); - - public sealed class CacheKey : IEquatable - { - private readonly int _value; - - public CacheKey(int value) - => _value = value; - - public bool Equals(CacheKey key) - => key._value == _value; - - public override bool Equals(object obj) - => ReferenceEquals(obj, this); - - public override int GetHashCode() - => _value; - - public override string ToString() - => _value.ToString(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/StringBuilderCache.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/StringBuilderCache.cs deleted file mode 100644 index 7203192666f..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/StringBuilderCache.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text; - -namespace Benchmarks.Data -{ - internal static class StringBuilderCache - { - private const int DefaultCapacity = 1386; - private const int MaxBuilderSize = DefaultCapacity * 3; - - [ThreadStatic] - private static StringBuilder t_cachedInstance; - - /// Get a StringBuilder for the specified capacity. - /// If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied. - public static StringBuilder Acquire(int capacity = DefaultCapacity) - { - if (capacity <= MaxBuilderSize) - { - StringBuilder sb = t_cachedInstance; - if (capacity < DefaultCapacity) - { - capacity = DefaultCapacity; - } - - if (sb != null) - { - // Avoid stringbuilder block fragmentation by getting a new StringBuilder - // when the requested size is larger than the current capacity - if (capacity <= sb.Capacity) - { - t_cachedInstance = null; - sb.Clear(); - return sb; - } - } - } - return new StringBuilder(capacity); - } - - public static void Release(StringBuilder sb) - { - if (sb.Capacity <= MaxBuilderSize) - { - t_cachedInstance = sb; - } - } - - public static string GetStringAndRelease(StringBuilder sb) - { - string result = sb.ToString(); - Release(sb); - return result; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Data/World.cs b/frameworks/CSharp/easyrpc/Benchmarks/Data/World.cs deleted file mode 100644 index adb4915467f..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Data/World.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Runtime.InteropServices; - -namespace Benchmarks.Data -{ - [StructLayout(LayoutKind.Sequential, Size = 8)] - public struct World - { - public int id { get; set; } - - public int randomNumber { get; set; } - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Program.cs b/frameworks/CSharp/easyrpc/Benchmarks/Program.cs deleted file mode 100644 index 7c91f4793eb..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Program.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Benchmarks -{ - using System.IO; - using System.Threading.Tasks; - using Microsoft.AspNetCore.Hosting; - using Microsoft.Extensions.Configuration; - - public class Program - { - public static async Task Main(string[] args) - { - var config = new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .AddEnvironmentVariables(prefix: "ASPNETCORE_") - .AddCommandLine(args) - .Build(); - - var webHost = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseConfiguration(config) - .UseStartup() - .UseKestrel() - .Build(); - - await webHost.RunAsync(); - } - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Services/FortuneService.cs b/frameworks/CSharp/easyrpc/Benchmarks/Services/FortuneService.cs deleted file mode 100644 index 4c7ebe6bf2c..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Services/FortuneService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using EasyRpc.Abstractions.Path; -using EasyRpc.AspNetCore.Views; -using Benchmarks.Data; -using System.Threading.Tasks; -using System.Collections.Generic; -using EasyRpc.Abstractions.Services; - -namespace Benchmarks -{ - [SharedService] - public class FortuneService - { - private IRawDb _rawDb; - - public FortuneService(IRawDb rawDb) => _rawDb = rawDb; - - [GetMethod("/Fortunes/Fortunes")] - [ReturnView(ContentType = "text/html; charset=utf-8")] - public Task> Fortunes() - { - return _rawDb.LoadFortunesRows(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Services/QueryService.cs b/frameworks/CSharp/easyrpc/Benchmarks/Services/QueryService.cs deleted file mode 100644 index 11f9ee54714..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Services/QueryService.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Threading.Tasks; -using Benchmarks.Data; -using EasyRpc.Abstractions.Path; -using EasyRpc.Abstractions.Services; - -namespace Benchmarks.Services -{ - [SharedService] - public class QueryService - { - private IRawDb _rawDb; - - public QueryService(IRawDb rawDb) - { - _rawDb = rawDb; - } - - [GetMethod("/db")] - public Task Single() - { - return _rawDb.LoadSingleQueryRow(); - } - - [GetMethod("/queries/{count}")] - public Task Multiple(int count = 1) - { - if(count < 1 ) - { - count = 1; - } - - if(count > 500) - { - count = 500; - } - - return _rawDb.LoadMultipleQueriesRows(count); - } - - [GetMethod("/updates/{count}")] - public Task Updates(int count = 1) - { - if(count < 1 ) - { - count = 1; - } - - if(count > 500) - { - count = 500; - } - - return _rawDb.LoadMultipleUpdatesRows(count); - } - - [GetMethod("/cached-worlds/{count}")] - public Task CachedWorlds(int count = 1) - { - if(count < 1 ) - { - count = 1; - } - - if(count > 500) - { - count = 500; - } - - return _rawDb.LoadCachedQueries(count); - } - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Startup.cs b/frameworks/CSharp/easyrpc/Benchmarks/Startup.cs deleted file mode 100644 index 797ae6dedc0..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Startup.cs +++ /dev/null @@ -1,59 +0,0 @@ -using EasyRpc.AspNetCore.Serializers; -using EasyRpc.AspNetCore.Utf8Json; -using Microsoft.Extensions.Configuration; - -namespace Benchmarks -{ - using System.Text.Encodings.Web; - using System.Text.Unicode; - using Benchmarks.Data; - using Benchmarks.Services; - using EasyRpc.AspNetCore; - using Microsoft.AspNetCore.Builder; - using Microsoft.Extensions.DependencyInjection; - - public class Startup - { - private IConfiguration _configuration; - - public Startup(IConfiguration configuration) - { - _configuration = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - services.AddRpcServices(c => c.RegisterJsonSerializer = false); - services.AddSingleton(); - services.AddSingleton(); - - var appSettings = new AppSettings(); - - _configuration.Bind(appSettings); - - services.AddSingleton(appSettings); - - // for views - services.AddControllersWithViews(); - var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, - UnicodeRanges.Katakana, - UnicodeRanges.Hiragana); - - settings.AllowCharacter('\u2014'); // allow EM DASH through - services.AddWebEncoders((options) => options.TextEncoderSettings = settings); - } - - public void Configure(IApplicationBuilder app) - { - app.UseRpcRouting(api => - { - api.Method.Get("/plaintext", () => "Hello, World!").Raw("text/plain"); - - api.Method.Get("/json", () => new { message = "Hello, World!" }); - - api.Expose(); - api.Expose(); - }); - } - } -} diff --git a/frameworks/CSharp/easyrpc/Benchmarks/Views/Fortunes/Fortunes.cshtml b/frameworks/CSharp/easyrpc/Benchmarks/Views/Fortunes/Fortunes.cshtml deleted file mode 100644 index 17d7ef14a24..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/Views/Fortunes/Fortunes.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@using Benchmarks.Data -@model List - - -Fortunes - - @foreach (var item in Model) - { - - } -
idmessage
@item.Id@item.Message
- diff --git a/frameworks/CSharp/easyrpc/Benchmarks/appsettings.json b/frameworks/CSharp/easyrpc/Benchmarks/appsettings.json deleted file mode 100644 index bca0e3446ca..00000000000 --- a/frameworks/CSharp/easyrpc/Benchmarks/appsettings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Delay Us=500;Write Coalescing Buffer Threshold Bytes=1000" -} diff --git a/frameworks/CSharp/easyrpc/README.md b/frameworks/CSharp/easyrpc/README.md deleted file mode 100755 index c5ed8548892..00000000000 --- a/frameworks/CSharp/easyrpc/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# EasyRpc Tests on Linux -This includes tests for plaintext and json serialization. - -## Infrastructure Software Versions - -**Language** - -* C# 7.0 - -**Platforms** - -* .NET Core (Windows and Linux) - -**Web Servers** - -* [Kestrel](https://github.com/aspnet/KestrelHttpServer) - -**Web Stack** - -* [EasyRpc](https://github.com/ipjohnson/EasyRpc) -* ASP.NET Core - -## Paths & Source for Tests - -* [Plaintext](Benchmarks/Startup.cs): "/plaintext" -* [JSON Serialization](Benchmarks/Startup.cs): "/json" -* [Single query](Benchmarks/Services/QueryService.cs): "/db" -* [Multiple query](Benchmarks/Services/QueryService.cs): "/queries" -* [Update query](Benchmarks/Services/QueryService.cs): "/updates" -* [Caching query](Benchmarks/Services/QueryService.cs): "/cached-worlds" -* [Fortune](Benchmarks/Services/FortuneService.cs): "/fortunes/fortunes" diff --git a/frameworks/CSharp/easyrpc/benchmark_config.json b/frameworks/CSharp/easyrpc/benchmark_config.json deleted file mode 100755 index da2069b745e..00000000000 --- a/frameworks/CSharp/easyrpc/benchmark_config.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "framework": "easyrpc", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes/fortunes", - "update_url": "/updates/", - "cached_query_url": "/cached-worlds/", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "EasyRpc", - "language": "C#", - "flavor": "CoreCLR", - "orm": "Raw", - "platform": ".Net", - "webserver": "Kestrel", - "os": "Linux", - "database_os": "Linux", - "display_name": "EasyRpc", - "notes": "", - "versus": "aspcore" - } - } - ] -} diff --git a/frameworks/CSharp/easyrpc/config.toml b/frameworks/CSharp/easyrpc/config.toml deleted file mode 100644 index 6ede177144d..00000000000 --- a/frameworks/CSharp/easyrpc/config.toml +++ /dev/null @@ -1,20 +0,0 @@ -[framework] -name = "easyrpc" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.update = "/updates/" -urls.fortune = "/fortunes/fortunes" -urls.cached_query = "/cached-worlds/" -approach = "Realistic" -classification = "Fullstack" -database = "postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = ".Net" -webserver = "Kestrel" -versus = "aspcore" diff --git a/frameworks/CSharp/easyrpc/easyrpc.dockerfile b/frameworks/CSharp/easyrpc/easyrpc.dockerfile deleted file mode 100644 index b120fb7ea05..00000000000 --- a/frameworks/CSharp/easyrpc/easyrpc.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build -WORKDIR /app -COPY Benchmarks . -RUN dotnet publish -c Release -o out - -FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime -ENV ASPNETCORE_URLS http://+:8080 -WORKDIR /app -COPY --from=build /app/out ./ - -EXPOSE 8080 - -ENTRYPOINT ["dotnet", "Benchmarks.dll"] diff --git a/frameworks/CSharp/effinitive/.gitignore b/frameworks/CSharp/effinitive/.gitignore new file mode 100644 index 00000000000..c8d1eed0116 --- /dev/null +++ b/frameworks/CSharp/effinitive/.gitignore @@ -0,0 +1,38 @@ +[Oo]bj/ +[Bb]in/ +TestResults/ +.nuget/ +*.sln +*.sln.ide/ +_ReSharper.*/ +.idea/ +packages/ +artifacts/ +PublishProfiles/ +.vs/ +*.user +*.suo +*.cache +*.docstates +_ReSharper.* +nuget.exe +*net45.csproj +*net451.csproj +*k10.csproj +*.psess +*.vsp +*.pidb +*.userprefs +*DS_Store +*.ncrunchsolution +*.*sdf +*.ipch +*.swp +*~ +.build/ +.testPublish/ +launchSettings.json +BenchmarkDotNet.Artifacts/ +BDN.Generated/ +binaries/ +global.json diff --git a/frameworks/CSharp/effinitive/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/effinitive/Benchmarks/Benchmarks.csproj new file mode 100644 index 00000000000..3361a3f214b --- /dev/null +++ b/frameworks/CSharp/effinitive/Benchmarks/Benchmarks.csproj @@ -0,0 +1,23 @@ + + + + + net10.0 + 14.0 + + Effinitive Benchmarks + Test suite to be executed with TechEmpower FrameworkBenchmarks. + + Benchmarks.Program + Exe + + true + false + + + + + + + + diff --git a/frameworks/CSharp/effinitive/Benchmarks/Benchmarks/Json.cs b/frameworks/CSharp/effinitive/Benchmarks/Benchmarks/Json.cs new file mode 100644 index 00000000000..ea5d5fb5d53 --- /dev/null +++ b/frameworks/CSharp/effinitive/Benchmarks/Benchmarks/Json.cs @@ -0,0 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; + +using EffinitiveFramework.Core; + +namespace Benchmarks.Benchmarks; + +public class JsonResult +{ + public string Message { get; set; } +} + +public class Json : NoRequestEndpointBase +{ + protected override string Method => "GET"; + + protected override string Route => "/json"; + + protected override string ContentType => "application/json; charset=utf-8"; + + public override ValueTask HandleAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult(new JsonResult() { Message = "Hello, World!" }); + } + +} diff --git a/frameworks/CSharp/effinitive/Benchmarks/Benchmarks/Plaintext.cs b/frameworks/CSharp/effinitive/Benchmarks/Benchmarks/Plaintext.cs new file mode 100644 index 00000000000..c49a43955a3 --- /dev/null +++ b/frameworks/CSharp/effinitive/Benchmarks/Benchmarks/Plaintext.cs @@ -0,0 +1,21 @@ +using System.Threading; +using System.Threading.Tasks; + +using EffinitiveFramework.Core; + +namespace Benchmarks.Benchmarks; + +public class Plaintext : NoRequestEndpointBase +{ + protected override string Method => "GET"; + + protected override string Route => "/plaintext"; + + protected override string ContentType => "text/plain"; + + public override ValueTask HandleAsync(CancellationToken cancellationToken = default) + { + return ValueTask.FromResult("Hello, World!"); + } + +} diff --git a/frameworks/CSharp/effinitive/Benchmarks/HttpComplianceMiddleware.cs b/frameworks/CSharp/effinitive/Benchmarks/HttpComplianceMiddleware.cs new file mode 100644 index 00000000000..c1a89c6f55e --- /dev/null +++ b/frameworks/CSharp/effinitive/Benchmarks/HttpComplianceMiddleware.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using EffinitiveFramework.Core.Http; +using EffinitiveFramework.Core.Middleware; + +namespace Benchmarks; + +public class HttpComplianceMiddleware : IMiddleware +{ + + public async ValueTask InvokeAsync(HttpRequest request, RequestDelegate next, CancellationToken cancellationToken) + { + var response = await next(request, cancellationToken); + + response.Headers.Add("Server", "Effinitive/1.1"); + response.Headers.Add("Date", DateTime.UtcNow.ToString("r")); + + return response; + } + +} diff --git a/frameworks/CSharp/effinitive/Benchmarks/Program.cs b/frameworks/CSharp/effinitive/Benchmarks/Program.cs new file mode 100644 index 00000000000..076e4b75885 --- /dev/null +++ b/frameworks/CSharp/effinitive/Benchmarks/Program.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using EffinitiveFramework.Core; + +namespace Benchmarks +{ + + public static class Program + { + private static readonly ManualResetEvent WaitEvent = new(false); + + public static async Task Main(string[] args) + { + var app = EffinitiveApp.Create() + .UsePort(8080) + .MapEndpoints() + .UseMiddleware() + .Build(); + + try + { + AppDomain.CurrentDomain.ProcessExit += (_, __) => + { + WaitEvent.Set(); + }; + + await app.RunAsync(); + + WaitEvent.WaitOne(); + + return 0; + } + catch (Exception e) + { + Console.WriteLine(e); + + return -1; + } + } + + } + +} diff --git a/frameworks/CSharp/effinitive/README.md b/frameworks/CSharp/effinitive/README.md new file mode 100644 index 00000000000..0b5228c00ef --- /dev/null +++ b/frameworks/CSharp/effinitive/README.md @@ -0,0 +1,22 @@ +# Effinitive Webserver Tests on Linux + +See the [project website](https://github.com/HBartosch/Effinitive) for more information. + +## Infrastructure Software Versions + +**Language** + +* C# 14.0 + +**Platforms** + +* .NET 10 + +**Web Servers** + +* [Effinitive Webserver](https://github.com/HBartosch/Effinitive) + +## Paths \& Source for Tests + +* [Plaintext](Benchmarks/Program.cs): "/plaintext" +* [JSON](Benchmarks/Program.cs): "/json" diff --git a/frameworks/CSharp/effinitive/benchmark_config.json b/frameworks/CSharp/effinitive/benchmark_config.json new file mode 100644 index 00000000000..ba84cc066de --- /dev/null +++ b/frameworks/CSharp/effinitive/benchmark_config.json @@ -0,0 +1,23 @@ +{ + "framework": "effinitive", + "maintainers": ["HBartosch"], + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "Effinitive", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "webserver": "Effinitive", + "os": "Linux", + "database_os": "Linux", + "display_name": "Effinitive Webserver", + "notes": "" + } + }] +} diff --git a/frameworks/CSharp/effinitive/config.toml b/frameworks/CSharp/effinitive/config.toml new file mode 100644 index 00000000000..403c4310a76 --- /dev/null +++ b/frameworks/CSharp/effinitive/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "effinitive" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Effinitive" +versus = "None" diff --git a/frameworks/CSharp/effinitive/effinitive.dockerfile b/frameworks/CSharp/effinitive/effinitive.dockerfile new file mode 100644 index 00000000000..13d219bd361 --- /dev/null +++ b/frameworks/CSharp/effinitive/effinitive.dockerfile @@ -0,0 +1,19 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY Benchmarks/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY Benchmarks/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["./Benchmarks"] + +EXPOSE 8080 \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj index 3a3b23ee153..896e4f2f86c 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj @@ -10,37 +10,70 @@ GenHTTP Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. - $(DefineConstants);$(GENHTTP_ENGINE_NAME) - + $(GENHTTP_ENGINE_NAME) + true true + false + + + + + + + + + + + - - + + - + + + - + - + - - + + + + + + + + + + + + + + + + + - - - + + + + + + + diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs deleted file mode 100644 index 37f08394aae..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextAssemblyAttributes.cs +++ /dev/null @@ -1,9 +0,0 @@ -// -using Benchmarks; -using Benchmarks.Model; -using Microsoft.EntityFrameworkCore.Infrastructure; - -#pragma warning disable 219, 612, 618 -#nullable disable - -[assembly: DbContextModel(typeof(DatabaseContext), typeof(DatabaseContextModel))] diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs deleted file mode 100644 index 1f4a1357bcc..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModel.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -using Benchmarks.Model; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; - -#pragma warning disable 219, 612, 618 -#nullable disable - -namespace Benchmarks -{ - [DbContext(typeof(DatabaseContext))] - public partial class DatabaseContextModel : RuntimeModel - { - private static readonly bool _useOldBehavior31751 = - System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751; - - static DatabaseContextModel() - { - var model = new DatabaseContextModel(); - - if (_useOldBehavior31751) - { - model.Initialize(); - } - else - { - var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024); - thread.Start(); - thread.Join(); - - void RunInitialization() - { - model.Initialize(); - } - } - - model.Customize(); - _instance = (DatabaseContextModel)model.FinalizeModel(); - } - - private static DatabaseContextModel _instance; - public static IModel Instance => _instance; - - partial void Initialize(); - - partial void Customize(); - } -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs deleted file mode 100644 index 763158097cb..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/DatabaseContextModelBuilder.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#pragma warning disable 219, 612, 618 -#nullable disable - -namespace Benchmarks -{ - public partial class DatabaseContextModel - { - private DatabaseContextModel() - : base(skipDetectChanges: false, modelId: new Guid("e6a922c5-5e25-4191-8617-6c6410b754cc"), entityTypeCount: 2) - { - } - - partial void Initialize() - { - var fortune = FortuneEntityType.Create(this); - var world = WorldEntityType.Create(this); - - FortuneEntityType.CreateAnnotations(fortune); - WorldEntityType.CreateAnnotations(world); - - AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - AddAnnotation("ProductVersion", "10.0.0"); - AddAnnotation("Relational:MaxIdentifierLength", 63); - } - } -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs deleted file mode 100644 index e89e9901b1a..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/FortuneEntityType.cs +++ /dev/null @@ -1,68 +0,0 @@ -// -using System; -using System.Reflection; -using Benchmarks.Model; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#pragma warning disable 219, 612, 618 -#nullable disable - -namespace Benchmarks -{ - [EntityFrameworkInternal] - public partial class FortuneEntityType - { - public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) - { - var runtimeEntityType = model.AddEntityType( - "Benchmarks.Model.Fortune", - typeof(Fortune), - baseEntityType, - propertyCount: 2, - keyCount: 1); - - var id = runtimeEntityType.AddProperty( - "Id", - typeof(int), - propertyInfo: typeof(Fortune).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), - fieldInfo: typeof(Fortune).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), - valueGenerated: ValueGenerated.OnAdd, - afterSaveBehavior: PropertySaveBehavior.Throw, - sentinel: 0); - id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - id.AddAnnotation("Relational:ColumnName", "id"); - - var message = runtimeEntityType.AddProperty( - "Message", - typeof(string), - propertyInfo: typeof(Fortune).GetProperty("Message", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), - fieldInfo: typeof(Fortune).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), - nullable: true, - maxLength: 2048); - message.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None); - message.AddAnnotation("Relational:ColumnName", "message"); - - var key = runtimeEntityType.AddKey( - new[] { id }); - runtimeEntityType.SetPrimaryKey(key); - - return runtimeEntityType; - } - - public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) - { - runtimeEntityType.AddAnnotation("Relational:FunctionName", null); - runtimeEntityType.AddAnnotation("Relational:Schema", null); - runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); - runtimeEntityType.AddAnnotation("Relational:TableName", "fortune"); - runtimeEntityType.AddAnnotation("Relational:ViewName", null); - runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); - - Customize(runtimeEntityType); - } - - static partial void Customize(RuntimeEntityType runtimeEntityType); - } -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs deleted file mode 100644 index 470b07a82b8..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/CompiledModel/WorldEntityType.cs +++ /dev/null @@ -1,67 +0,0 @@ -// -using System; -using System.Reflection; -using Benchmarks.Model; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#pragma warning disable 219, 612, 618 -#nullable disable - -namespace Benchmarks -{ - [EntityFrameworkInternal] - public partial class WorldEntityType - { - public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) - { - var runtimeEntityType = model.AddEntityType( - "Benchmarks.Model.World", - typeof(World), - baseEntityType, - propertyCount: 2, - keyCount: 1); - - var id = runtimeEntityType.AddProperty( - "Id", - typeof(int), - propertyInfo: typeof(World).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), - fieldInfo: typeof(World).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), - valueGenerated: ValueGenerated.OnAdd, - afterSaveBehavior: PropertySaveBehavior.Throw, - sentinel: 0); - id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - id.AddAnnotation("Relational:ColumnName", "id"); - - var randomNumber = runtimeEntityType.AddProperty( - "RandomNumber", - typeof(int), - propertyInfo: typeof(World).GetProperty("RandomNumber", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), - fieldInfo: typeof(World).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), - sentinel: 0); - randomNumber.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None); - randomNumber.AddAnnotation("Relational:ColumnName", "randomnumber"); - - var key = runtimeEntityType.AddKey( - new[] { id }); - runtimeEntityType.SetPrimaryKey(key); - - return runtimeEntityType; - } - - public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) - { - runtimeEntityType.AddAnnotation("Relational:FunctionName", null); - runtimeEntityType.AddAnnotation("Relational:Schema", null); - runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); - runtimeEntityType.AddAnnotation("Relational:TableName", "world"); - runtimeEntityType.AddAnnotation("Relational:ViewName", null); - runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); - - Customize(runtimeEntityType); - } - - static partial void Customize(RuntimeEntityType runtimeEntityType); - } -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs index c49a8e9d1a4..e1335a014ed 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/Database.cs @@ -1,15 +1,17 @@ -namespace Benchmarks.Model; +namespace Benchmarks.Model; + +using Npgsql; public static class Database { - public static readonly DatabaseContextPool NoTrackingPool; - - public static readonly DatabaseContextPool TrackingPool; + + public static readonly NpgsqlDataSource DataSource = BuildDataSource(); - static Database() + private static NpgsqlDataSource BuildDataSource() { - NoTrackingPool = new DatabaseContextPool(factory: DatabaseContext.CreateNoTracking, maxSize: 512); - TrackingPool = new DatabaseContextPool(factory: DatabaseContext.CreateTracking, maxSize: 512); + var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION"); + + return new NpgsqlSlimDataSourceBuilder(connectionString).EnableArrays().Build(); } - + } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs deleted file mode 100644 index bedd6a38454..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; - -namespace Benchmarks.Model; - -public sealed class DatabaseContext : DbContext -{ - private static readonly Lazy> TrackingOptions = new(() => CreateOptions(true), LazyThreadSafetyMode.ExecutionAndPublication); - - private static readonly Lazy> NoTrackingOptions = new(() => CreateOptions(false), LazyThreadSafetyMode.ExecutionAndPublication); - - public static DatabaseContext CreateTracking() => new(TrackingOptions.Value, true); - - public static DatabaseContext CreateNoTracking() => new(NoTrackingOptions.Value, false); - - private static DbContextOptions CreateOptions(bool tracking) - { - var services = new ServiceCollection(); - - services.AddEntityFrameworkNpgsql(); - - var provider = services.BuildServiceProvider(); - - var builder = new DbContextOptionsBuilder(); - - builder.UseInternalServiceProvider(provider) - .UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=512;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true") - .EnableThreadSafetyChecks(false) - .UseModel(DatabaseContextModel.Instance); - - if (!tracking) - { - builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); - } - - return builder.Options; - } - - internal DatabaseContext(DbContextOptions options, bool tracking = false) : base(options) - { - ChangeTracker.AutoDetectChangesEnabled = tracking; - } - - public DbSet World { get; set; } - - public DbSet Fortune { get; set; } - -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs deleted file mode 100644 index 8c6c62c83ac..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Benchmarks.Model; - -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Design; - -public class DatabaseContextFactory : IDesignTimeDbContextFactory -{ - - public DatabaseContext CreateDbContext(string[] args) - { - var options = new DbContextOptionsBuilder() - .UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable") - .Options; - - return new DatabaseContext(options); - } - -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs deleted file mode 100644 index aaec09ccf53..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContextPool.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Benchmarks.Model; - -using System.Collections.Concurrent; - -using Microsoft.EntityFrameworkCore; - -public sealed class DatabaseContextPool where TContext : DbContext -{ - private readonly ConcurrentBag _pool = new(); - - private readonly Func _factory; - - private readonly int _maxSize; - - public DatabaseContextPool(Func factory, int maxSize) - { - _factory = factory; - _maxSize = maxSize; - } - - public TContext Rent() - { - if (_pool.TryTake(out var ctx)) - { - ctx.ChangeTracker.Clear(); - return ctx; - } - - return _factory(); - } - - public void Return(TContext context) - { - if (_pool.Count >= _maxSize) - { - context.Dispose(); - return; - } - - - context.ChangeTracker.Clear(); - - _pool.Add(context); - } - -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/FortuneMap.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/FortuneMap.cs new file mode 100644 index 00000000000..cf80593b746 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/FortuneMap.cs @@ -0,0 +1,80 @@ +using System.Collections; +using Cottle; + +namespace Benchmarks.Model; + +public readonly struct FortuneMap : IMap +{ + private readonly int _id; + private readonly string _message; + + public FortuneMap(int id, string message) + { + _id = id; + _message = message; + } + + public Value this[Value key] => TryGet(key, out var value) ? value : Value.Undefined; + + public int Count => 2; + + public bool Contains(Value key) + { + var keyStr = key.AsString; + return keyStr == "id" || keyStr == "message"; + } + + public bool TryGet(Value key, out Value value) + { + var keyStr = key.AsString; + if (keyStr == "id") + { + value = _id; + return true; + } + if (keyStr == "message") + { + value = _message; + return true; + } + + value = Value.Undefined; + return false; + } + + public int CompareTo(IMap other) + { + if (other == null) return 1; + + if (other.TryGet("id", out var otherId)) + { + return _id.CompareTo(otherId.AsNumber); + } + + return Count.CompareTo(other.Count); + } + + public bool Equals(IMap other) + { + if (other == null || other.Count != Count) + return false; + + return other.TryGet("id", out var otherId) && + other.TryGet("message", out var otherMsg) && + _id == (int)otherId.AsNumber && + _message == otherMsg.AsString; + } + + public IEnumerator> GetEnumerator() + { + yield return new KeyValuePair("id", _id); + yield return new KeyValuePair("message", _message); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public override bool Equals(object obj) => obj is IMap map && Equals(map); + + public override int GetHashCode() => HashCode.Combine(_id, _message); + +} \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.Internal.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.Internal.cs new file mode 100644 index 00000000000..3813f5ae438 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Program.Internal.cs @@ -0,0 +1,9 @@ +using Benchmarks; + +using GenHTTP.Engine.Internal; + +var project = Project.Create(); + +return await Host.Create() + .Handler(project) + .RunAsync(); diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.Kestrel.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.Kestrel.cs new file mode 100644 index 00000000000..41779a8abc8 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Program.Kestrel.cs @@ -0,0 +1,9 @@ +using Benchmarks; + +using GenHTTP.Engine.Kestrel; + +var project = Project.Create(); + +return await Host.Create() + .Handler(project) + .RunAsync(); diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.Unhinged.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.Unhinged.cs new file mode 100644 index 00000000000..f5d91eee4a5 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Program.Unhinged.cs @@ -0,0 +1,17 @@ +using Benchmarks; + +using Unhinged; +using Unhinged.GenHttp.Experimental; + +var project = Project.Create(); + +UnhingedEngine.CreateBuilder() + .SetPort(8080) + .SetNWorkersSolver(() => Environment.ProcessorCount) + .SetBacklog(16384) + .SetMaxEventsPerWake(512) + .SetMaxNumberConnectionsPerWorker(1024) + .SetSlabSizes(32 * 1024, 16 * 1024) + .Map(project) + .Build() + .Run(); diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.Wired.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.Wired.cs new file mode 100644 index 00000000000..b46e28cada0 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Program.Wired.cs @@ -0,0 +1,14 @@ +using Benchmarks; + +using GenHTTP.Adapters.WiredIO; + +using Wired.IO.App; + +var project = Project.Create(); + +await WiredApp.CreateExpressBuilder() + .Port(8080) + .MapGenHttp("*", project) + .Build() + .RunAsync(); + \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.cs deleted file mode 100644 index 91323662c2d..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Program.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Benchmarks.Tests; -using Benchmarks.Utilities; - -#if INTERNAL -using GenHTTP.Engine.Internal; -#else -using GenHTTP.Engine.Kestrel; -#endif - -using GenHTTP.Modules.IO; -using GenHTTP.Modules.Layouting; -using GenHTTP.Modules.Webservices; - -var tests = Layout.Create() - .Add("plaintext", Content.From(Resource.FromString("Hello, World!"))) - .Add("json", new JsonHandler()) - .Add("fortunes", new FortuneHandler()) - .AddService("db") - .AddService("queries") - .AddService("updates") - .AddService("cached-worlds") - .Add(ServerHeader.Create()); - -return await Host.Create() - .Handler(tests) - .RunAsync(); diff --git a/frameworks/CSharp/genhttp/Benchmarks/Project.cs b/frameworks/CSharp/genhttp/Benchmarks/Project.cs new file mode 100644 index 00000000000..13bae801b07 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Project.cs @@ -0,0 +1,31 @@ +using Benchmarks.Tests; +using Benchmarks.Utilities; + +using GenHTTP.Api.Content; + +using GenHTTP.Modules.IO; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.Reflection; +using GenHTTP.Modules.Webservices; + +namespace Benchmarks; + +public static class Project +{ + + public static IHandlerBuilder Create() + { + var mode = ExecutionMode.Auto; + + return Layout.Create() + .Add("plaintext", Content.From(Resource.FromString("Hello, World!"))) + .Add("json", new JsonHandler()) + .Add("fortunes", new FortuneHandler()) + .AddService("db", mode: mode) + .AddService("queries", mode: mode) + .AddService("updates", mode: mode) + .AddService("cached-worlds", mode: mode) + .Add(ServerHeader.Create()); + } + +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs index 5a899bcadfd..cb7a5a96215 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs @@ -1,20 +1,26 @@ -using Benchmarks.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Benchmarks.Model; + using GenHTTP.Modules.Webservices; -using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Caching.Memory; +using Npgsql; + namespace Benchmarks.Tests; public sealed class CacheResource { - private static readonly Random Random = new(); - private static readonly MemoryCache Cache = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromMinutes(60) }); - private static readonly object[] CacheKeys = Enumerable.Range(0, 10001).Select(i => new CacheKey(i)).ToArray(); + private static readonly CacheKey[] CacheKeys = Enumerable.Range(0, 10001).Select(i => new CacheKey(i)).ToArray(); [ResourceMethod(":queries")] public ValueTask> GetWorldsFromPath(string queries) => GetWorlds(queries); @@ -22,9 +28,10 @@ public sealed class CacheResource [ResourceMethod] public async ValueTask> GetWorlds(string queries) { - var count = 1; - - int.TryParse(queries, out count); + if (!int.TryParse(queries, out var count)) + { + count = 1; + } if (count < 1) { @@ -35,40 +42,60 @@ public async ValueTask> GetWorlds(string queries) count = 500; } - var result = new List(count); + NpgsqlConnection connection = null; - var context = Database.NoTrackingPool.Rent(); + var result = new List(count); - try + for (var i = 0; i < count; i++) { - for (var i = 0; i < count; i++) - { - var id = Random.Next(1, 10001); + var id = Random.Shared.Next(1, 10001); - var key = CacheKeys[id]; + var key = CacheKeys[id]; - var data = Cache.Get(key); + var data = Cache.Get(key); - if (data != null) + if (data != null) + { + result.Add(data); + } + else + { + if (connection == null) { - result.Add(data); + connection = await Database.DataSource.OpenConnectionAsync(); } - else - { - var resolved = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - Cache.Set(key, resolved); + var resolved = await GetWorldById(connection, id); - result.Add(resolved); - } + Cache.Set(key, resolved); + + result.Add(resolved); } } - finally + + return result; + } + + private static async Task GetWorldById(NpgsqlConnection connection, int id) + { + await using var command = connection.CreateCommand(); + + command.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id"; + + command.Parameters.AddWithValue("@Id", id); + + await using var reader = await command.ExecuteReaderAsync(); + + if (await reader.ReadAsync()) { - Database.NoTrackingPool.Return(context); + return new() + { + Id = reader.GetInt32(0), + RandomNumber = reader.GetInt32(1) + }; } - return result; + return null; } public sealed class CacheKey : IEquatable @@ -88,4 +115,5 @@ public CacheKey(int value) public override string ToString() => _value.ToString(); } + } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs index 3363db1180d..e7363d438b4 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs @@ -1,28 +1,36 @@ using Benchmarks.Model; using GenHTTP.Modules.Webservices; -using Microsoft.EntityFrameworkCore; namespace Benchmarks.Tests; public sealed class DbResource { - private static readonly Random Random = new(); [ResourceMethod] - public async ValueTask GetRandomWorld() + public Task GetRandomWorld() => GetWorldById(Random.Shared.Next(1, 10001)); + + private static async Task GetWorldById(int id) { - var id = Random.Next(1, 10001); + await using var connection = await Database.DataSource.OpenConnectionAsync(); - var context = Database.NoTrackingPool.Rent(); + await using var command = connection.CreateCommand(); - try - { - return await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - } - finally + command.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id"; + + command.Parameters.AddWithValue("@Id", id); + + await using var reader = await command.ExecuteReaderAsync(); + + if (await reader.ReadAsync()) { - Database.NoTrackingPool.Return(context); + return new() + { + Id = reader.GetInt32(0), + RandomNumber = reader.GetInt32(1) + }; } + + return null; } } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs index 5f4f6d8860c..b3b3fab47f4 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs @@ -1,92 +1,106 @@ -using System.Web; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Web; using Benchmarks.Model; + using Cottle; + using GenHTTP.Api.Content; using GenHTTP.Api.Protocol; using GenHTTP.Modules.IO; using GenHTTP.Modules.Pages; -using GenHTTP.Modules.Pages.Rendering; - -using Microsoft.EntityFrameworkCore; namespace Benchmarks.Tests; public class FortuneHandler : IHandler { + private IDocument _template; - #region Get-/Setters - - private TemplateRenderer Template { get; } - - #endregion - - #region Initialization + #region Functionality - public FortuneHandler() + public async ValueTask PrepareAsync() { var resource = Resource.FromAssembly("Template.html").Build(); - Template = Renderer.From(resource); + using var reader = new StreamReader(await resource.GetContentAsync()); + + _template = Document.CreateDefault(reader).DocumentOrThrow; } - #endregion - - #region Functionality - - public ValueTask PrepareAsync() => new(); - public async ValueTask HandleAsync(IRequest request) { - var data = new Dictionary + if (_template == null) { - ["cookies"] = Value.FromEnumerable(await GetFortunes()) - }; + await PrepareAsync(); + } + + var template = _template ?? throw new InvalidOperationException("Template has not been initialized"); + + var fortunes = await GetFortunes(); + + var context = BuildContext(fortunes); - return request.GetPage(await Template.RenderAsync(data)).Build(); + var content = template.Render(context); + + return request.GetPage(content).Build(); } - private static async ValueTask> GetFortunes() + private static async Task> GetFortunes() { - var context = Database.NoTrackingPool.Rent(); - - try - { - var fortunes = await context.Fortune.ToListAsync().ConfigureAwait(false); + var fortunes = await QueryDatabaseAsync(); + + fortunes.Add(new() { Id = 0, Message = "Additional fortune added at request time." }); + + fortunes.Sort((x, y) => string.CompareOrdinal(x.Message, y.Message)); + + return fortunes; + } - var result = new List(fortunes.Count + 1); + private static async Task> QueryDatabaseAsync() + { + await using var connection = await Database.DataSource.OpenConnectionAsync(); - foreach (var fortune in fortunes) - { - result.Add(Value.FromDictionary(new Dictionary() - { - ["id"] = fortune.Id, - ["message"] = HttpUtility.HtmlEncode(fortune.Message) - })); - } - - result.Add(Value.FromDictionary(new Dictionary() - { - ["id"] = 0, - ["message"] = "Additional fortune added at request time." - })); + await using var command = connection.CreateCommand(); - result.Sort((one, two) => + command.CommandText = "SELECT id, message FROM fortune"; + + var result = new List(16); + + await using var reader = await command.ExecuteReaderAsync(); + + while (await reader.ReadAsync()) + { + result.Add(new () { - var firstMessage = one.Fields["message"].AsString; - var secondMessage = two.Fields["message"].AsString; - - return string.Compare(firstMessage, secondMessage, StringComparison.Ordinal); + Id = reader.GetInt32(0), + Message = HttpUtility.HtmlEncode(reader.GetString(1)) }); - - return result; } - finally + + return result; + } + + private static IContext BuildContext(List cookies) + { + var values = new Value[cookies.Count]; + + for (var i = 0; i < cookies.Count; i++) { - Database.NoTrackingPool.Return(context); + values[i] = Value.FromMap(new FortuneMap(cookies[i].Id, cookies[i].Message)); } + + var store = new Dictionary + { + ["cookies"] = Value.FromEnumerable(values.ToArray()) + }; + + return Context.CreateBuiltin(store); } - + #endregion - + } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs index e9a0877f542..3bf10aef302 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs @@ -1,22 +1,28 @@ -using Benchmarks.Model; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using Benchmarks.Model; + using GenHTTP.Modules.Webservices; -using Microsoft.EntityFrameworkCore; + +using NpgsqlTypes; namespace Benchmarks.Tests; public sealed class QueryResource { - private static readonly Random Random = new(); [ResourceMethod(":queries")] - public ValueTask> GetWorldsFromPath(string queries) => GetWorlds(queries); + public Task> GetWorldsFromPath(string queries) => GetWorlds(queries); [ResourceMethod] - public async ValueTask> GetWorlds(string queries) + public Task> GetWorlds(string queries) { - var count = 1; - - int.TryParse(queries, out count); + if (!int.TryParse(queries, out var count)) + { + count = 1; + } if (count < 1) { @@ -27,24 +33,37 @@ public async ValueTask> GetWorlds(string queries) count = 500; } + return GetRandomWorlds(count); + } + + private static async Task> GetRandomWorlds(int count) + { var result = new List(count); - var context = Database.NoTrackingPool.Rent(); + await using var connection = await Database.DataSource.OpenConnectionAsync(); - try + await using var command = connection.CreateCommand(); + + command.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id"; + + var parameter = command.Parameters.Add("@Id", NpgsqlDbType.Integer); + + for (var i = 0; i < count; i++) { - for (var _ = 0; _ < count; _++) - { - var id = Random.Next(1, 10001); + parameter.Value = Random.Shared.Next(1, 10001); + + await using var reader = await command.ExecuteReaderAsync(); - result.Add(await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false)); + if (await reader.ReadAsync()) + { + result.Add(new() + { + Id = reader.GetInt32(0), + RandomNumber = reader.GetInt32(1) + }); } } - finally - { - Database.NoTrackingPool.Return(context); - } - + return result; } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs index 826c30a7bd3..deb58893776 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs @@ -1,22 +1,28 @@ -using Benchmarks.Model; +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Benchmarks.Model; + using GenHTTP.Modules.Webservices; -using Microsoft.EntityFrameworkCore; + +using Npgsql; +using NpgsqlTypes; namespace Benchmarks.Tests; public sealed class UpdateResource { - private static readonly Random Random = new(); [ResourceMethod(":queries")] - public ValueTask> UpdateWorldsFromPath(string queries) => UpdateWorlds(queries); + public ValueTask UpdateWorldsFromPath(string queries) => UpdateWorlds(queries); [ResourceMethod] - public async ValueTask> UpdateWorlds(string queries) + public ValueTask UpdateWorlds(string queries) { - var count = 1; - - int.TryParse(queries, out count); + if (!int.TryParse(queries, out var count)) + { + count = 1; + } if (count < 1) { @@ -26,45 +32,87 @@ public async ValueTask> UpdateWorlds(string queries) { count = 500; } + + return FetchAndUpdateWorlds(count); + } - var result = new List(count); + private async ValueTask FetchAndUpdateWorlds(int count) + { + var results = new World[count]; - var ids = Enumerable.Range(1, 10000).Select(x => Random.Next(1, 10001)).Distinct().Take(count).ToArray(); + var ids = new int[count]; + var numbers = new int[count]; - var context = Database.TrackingPool.Rent(); + for (var i = 0; i < count; i++) + { + ids[i] = Random.Shared.Next(1, 10001); + } + + Array.Sort(ids); + + for (var i = 1; i < count; i++) + if (ids[i] == ids[i - 1]) + ids[i] = (ids[i] % 10000) + 1; + + using var connection = await Database.DataSource.OpenConnectionAsync(); + + // Each row must be selected randomly using one query in the same fashion as the single database query test + // Use of IN clauses or similar means to consolidate multiple queries into one operation is not permitted. + // Similarly, use of a batch or multiple SELECTs within a single statement are not permitted + var (queryCmd, queryParameter) = CreateReadCommand(connection); + using (queryCmd) + { + for (var i = 0; i < results.Length; i++) + { + queryParameter.TypedValue = ids[i]; + results[i] = await ReadSingleRow(queryCmd); + } + } - try + for (var i = 0; i < count; i++) { - foreach (var id in ids) + var randomNumber = Random.Shared.Next(1, 10001); + if (results[i].RandomNumber == randomNumber) { - var record = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); + randomNumber = (randomNumber % 10000) + 1; + } - var old = record.RandomNumber; + results[i].RandomNumber = randomNumber; + numbers[i] = randomNumber; + } - var current = old; + var update = "UPDATE world w SET randomnumber = u.new_val FROM (SELECT unnest($1) as id, unnest($2) as new_val) u WHERE w.id = u.id"; - for (var i = 0; i < 5; i++) - { - current = Random.Next(1, 10001); + using var updateCmd = new NpgsqlCommand(update, connection); + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = ids, NpgsqlDbType = NpgsqlDbType.Array | NpgsqlDbType.Integer }); + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = numbers, NpgsqlDbType = NpgsqlDbType.Array | NpgsqlDbType.Integer }); - if (current != old) - { - break; - } - } + await updateCmd.ExecuteNonQueryAsync(); - record.RandomNumber = current; + return results; + } + + private (NpgsqlCommand readCmd, NpgsqlParameter idParameter) CreateReadCommand(NpgsqlConnection connection) + { + var cmd = new NpgsqlCommand("SELECT id, randomnumber FROM world WHERE id = $1", connection); + var parameter = new NpgsqlParameter { TypedValue = Random.Shared.Next(1, 10001) }; - result.Add(record); + cmd.Parameters.Add(parameter); - await context.SaveChangesAsync(); - } - } - finally - { - Database.TrackingPool.Return(context); - } + return (cmd, parameter); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task ReadSingleRow(NpgsqlCommand cmd) + { + using var rdr = await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.SingleRow); + await rdr.ReadAsync(); - return result; + return new World + { + Id = rdr.GetInt32(0), + RandomNumber = rdr.GetInt32(1) + }; } + } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs b/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs index 7ef372c65f0..fd30d959589 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs @@ -8,13 +8,13 @@ namespace Benchmarks.Utilities; public sealed class FixedLengthJsonContent : IResponseContent { - private readonly MemoryStream _buffer = new(); + private readonly MemoryStream _buffer = new(27); public ulong? Length => (ulong)_buffer.Length; public FixedLengthJsonContent(JsonResult result) { - JsonSerializer.SerializeAsync(_buffer, result); + JsonSerializer.Serialize(_buffer, result); } public ValueTask CalculateChecksumAsync() => throw new NotImplementedException(); diff --git a/frameworks/CSharp/genhttp/benchmark_config.json b/frameworks/CSharp/genhttp/benchmark_config.json index f2376bf64fc..0f024d1b5ba 100644 --- a/frameworks/CSharp/genhttp/benchmark_config.json +++ b/frameworks/CSharp/genhttp/benchmark_config.json @@ -45,6 +45,50 @@ "database_os": "Linux", "display_name": "genhttp [kestrel]", "notes": "" + }, + "wired": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "update_url": "/updates/", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds/", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "GenHTTP", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "webserver": "Wired.IO", + "os": "Linux", + "database_os": "Linux", + "display_name": "genhttp [wired.io]", + "notes": "" + }, + "unhinged": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "update_url": "/updates/", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds/", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "GenHTTP", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "webserver": "Unhinged", + "os": "Linux", + "database_os": "Linux", + "display_name": "genhttp [unhinged]", + "notes": "" } }] } diff --git a/frameworks/CSharp/genhttp/config.toml b/frameworks/CSharp/genhttp/config.toml index 538213c05b4..2338b765a36 100644 --- a/frameworks/CSharp/genhttp/config.toml +++ b/frameworks/CSharp/genhttp/config.toml @@ -36,3 +36,39 @@ orm = "Raw" platform = ".NET" webserver = "Kestrel" versus = "None" + +[wired] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-worlds/" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Wired.IO" +versus = "None" + +[unhinged] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-worlds/" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Unhinged" +versus = "None" diff --git a/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile b/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile index e345a538f34..bc85d2b34e0 100644 --- a/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile +++ b/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile @@ -1,8 +1,7 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build WORKDIR /source -ENV GENHTTP_ENGINE_NAME=KESTREL -ENV GENHTTP_ENGINE_PACKAGE=GenHTTP.Core.Kestrel +ENV GENHTTP_ENGINE_NAME=Kestrel # copy csproj and restore as distinct layers COPY Benchmarks/*.csproj . @@ -17,13 +16,12 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ENV DOTNET_GCDynamicAdaptationMode=0 \ DOTNET_EnableDiagnostics=0 \ - COMPlus_EnableDiagnostics=0 \ - COMPlus_DbgEnableMiniDump=0 \ - COMPlus_DbgEnableMiniDumpCollection=0 \ - COMPlus_DbgMiniDumpType=0 \ - DOTNET_TieredPGO=0 \ - DOTNET_TC_QuickJitForLoops=1 \ - DOTNET_TC_QuickJit=1 + DOTNET_TieredPGO=1 \ + DOTNET_TC_QuickJitForLoops=0 \ + DOTNET_ReadyToRun=0 \ + DOTNET_TieredCompilation=0 \ + DOTNET_gcServer=1 \ + DB_CONNECTION="Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000;" WORKDIR /app COPY --from=build /app . diff --git a/frameworks/CSharp/genhttp/genhttp-unhinged.dockerfile b/frameworks/CSharp/genhttp/genhttp-unhinged.dockerfile new file mode 100644 index 00000000000..ba540aa46d0 --- /dev/null +++ b/frameworks/CSharp/genhttp/genhttp-unhinged.dockerfile @@ -0,0 +1,31 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build +WORKDIR /source + +ENV GENHTTP_ENGINE_NAME=Unhinged + +# copy csproj and restore as distinct layers +COPY Benchmarks/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY Benchmarks/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine + +ENV DOTNET_GCDynamicAdaptationMode=0 \ + DOTNET_EnableDiagnostics=0 \ + DOTNET_TieredPGO=1 \ + DOTNET_TC_QuickJitForLoops=0 \ + DOTNET_ReadyToRun=0 \ + DOTNET_TieredCompilation=0 \ + DOTNET_gcServer=1 \ + DB_CONNECTION="Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000;" + +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["./Benchmarks"] + +EXPOSE 8080 diff --git a/frameworks/CSharp/genhttp/genhttp-wired.dockerfile b/frameworks/CSharp/genhttp/genhttp-wired.dockerfile new file mode 100644 index 00000000000..9011e6ef2f0 --- /dev/null +++ b/frameworks/CSharp/genhttp/genhttp-wired.dockerfile @@ -0,0 +1,31 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build +WORKDIR /source + +ENV GENHTTP_ENGINE_NAME=Wired + +# copy csproj and restore as distinct layers +COPY Benchmarks/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY Benchmarks/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained + +# final stage/image +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine + +ENV DOTNET_GCDynamicAdaptationMode=0 \ + DOTNET_EnableDiagnostics=0 \ + DOTNET_TieredPGO=1 \ + DOTNET_TC_QuickJitForLoops=0 \ + DOTNET_ReadyToRun=0 \ + DOTNET_TieredCompilation=0 \ + DOTNET_gcServer=1 \ + DB_CONNECTION="Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000;" + +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["./Benchmarks"] + +EXPOSE 8080 diff --git a/frameworks/CSharp/genhttp/genhttp.dockerfile b/frameworks/CSharp/genhttp/genhttp.dockerfile index 9414123202e..2280d4c2b53 100644 --- a/frameworks/CSharp/genhttp/genhttp.dockerfile +++ b/frameworks/CSharp/genhttp/genhttp.dockerfile @@ -1,8 +1,7 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build WORKDIR /source -ENV GENHTTP_ENGINE_NAME=INTERNAL -ENV GENHTTP_ENGINE_PACKAGE=GenHTTP.Core +ENV GENHTTP_ENGINE_NAME=Internal # copy csproj and restore as distinct layers COPY Benchmarks/*.csproj . @@ -17,13 +16,12 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ENV DOTNET_GCDynamicAdaptationMode=0 \ DOTNET_EnableDiagnostics=0 \ - COMPlus_EnableDiagnostics=0 \ - COMPlus_DbgEnableMiniDump=0 \ - COMPlus_DbgEnableMiniDumpCollection=0 \ - COMPlus_DbgMiniDumpType=0 \ - DOTNET_TieredPGO=0 \ - DOTNET_TC_QuickJitForLoops=1 \ - DOTNET_TC_QuickJit=1 + DOTNET_TieredPGO=1 \ + DOTNET_TC_QuickJitForLoops=0 \ + DOTNET_ReadyToRun=0 \ + DOTNET_TieredCompilation=0 \ + DOTNET_gcServer=1 \ + DB_CONNECTION="Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000;" WORKDIR /app COPY --from=build /app . diff --git a/frameworks/CSharp/nancy/.gitignore b/frameworks/CSharp/nancy/.gitignore deleted file mode 100644 index 708c4155fa7..00000000000 --- a/frameworks/CSharp/nancy/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -[Oo]bj/ -[Bb]in/ -TestResults/ -.nuget/ -*.sln.ide/ -_ReSharper.*/ -.idea/ -packages/ -artifacts/ -PublishProfiles/ -.vs/ -*.user -*.suo -*.cache -*.docstates -_ReSharper.* -nuget.exe -*net45.csproj -*net451.csproj -*k10.csproj -*.psess -*.vsp -*.pidb -*.userprefs -*DS_Store -*.ncrunchsolution -*.*sdf -*.ipch -*.swp -*~ -.build/ -.testPublish/ -launchSettings.json -BenchmarkDotNet.Artifacts/ -BDN.Generated/ -binaries/ -global.json diff --git a/frameworks/CSharp/nancy/README.md b/frameworks/CSharp/nancy/README.md deleted file mode 100644 index f881dd642c6..00000000000 --- a/frameworks/CSharp/nancy/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Nancy on Mono and CoreCLR Benchmarking Test - -The information below contains information specific to Nancy on Mono and CoreCLR. -For further guidance, review the -[documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). -Also note the additional information provided in the [CSharp README](../). - -This is the Nancy on Mono and CoreCLR portion of a [benchmarking test suite](../../) -comparing a variety of web platforms. - -## Infrastructure Software Versions - -**Language** - -* C# 7.2 - -**Platforms** - -* Mono 5.12.X (Linux) -* CoreCLR 2.1 (Linux) - -**Web Servers** - -* Kestrel (Linux) - -**Web Stack** - -* ASP.NET Core 2.1 -* Nancy 2.0.0 - -**Databases** - -* MySQL Connector + Dapper (ORM) - -**Developer Tools** - -* Visual Studio 2017 - -## Paths & Source for Tests - -* [Plaintext](src/PlainModule.cs): "/plaintext" -* [JSON Serialization](src/JsonModule.cs): "/json" - -### Nancy - Dapper (ORM) - -* [Single Database Query](src/DbModule.cs): "/db" -* [Multiple Database Queries](src/QueryModule.cs): "/query/10" - -## Add a New Test for Nancy - -### Platform Installation - -[Install Mono on Linux](https://www.mono-project.com/download/stable/#download-lin) - -[Install CoreCLR on Linux](hhttps://www.microsoft.com/net/download/linux/build) - -## Get Help - -### Experts - -_There aren't any experts listed, yet. If you're an expert, add yourself!_ - -### Community - -* Chat in the [#NancyFX](https://jabbr.net/account/login?ReturnUrl=%2F#/rooms/nancyfx) room on JabbR. -* #NancyFx on Twitter. - -### Resources - -* [Source Code](https://github.com/NancyFx/Nancy) -* [Issue #877 - Discussion regarding Event2.dll and Global.asax thread configuration](https://github.com/TechEmpower/FrameworkBenchmarks/issues/877) diff --git a/frameworks/CSharp/nancy/benchmark_config.json b/frameworks/CSharp/nancy/benchmark_config.json deleted file mode 100644 index 60286ac81ae..00000000000 --- a/frameworks/CSharp/nancy/benchmark_config.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "framework": "nancy", - "tests": [{ - "default": { - "plaintext_url":"/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "nancy", - "language": "C#", - "flavor": "Mono", - "orm": "Micro", - "platform": ".NET", - "webserver": "Kestrel", - "os": "Linux", - "database_os": "Linux", - "display_name": "Nancy [ASP.NET Core, Mono, My]", - "notes": "", - "versus": "aspcore-mono" - }, - "netcore": { - "plaintext_url":"/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "nancy", - "language": "C#", - "flavor": "CoreCLR", - "orm": "Micro", - "platform": ".NET", - "webserver": "Kestrel", - "os": "Linux", - "database_os": "Linux", - "display_name": "Nancy [ASP.NET Core, My]", - "notes": "", - "versus": "aspcore" - } - }] -} diff --git a/frameworks/CSharp/nancy/config.toml b/frameworks/CSharp/nancy/config.toml deleted file mode 100644 index cbffc2ed88f..00000000000 --- a/frameworks/CSharp/nancy/config.toml +++ /dev/null @@ -1,32 +0,0 @@ -[framework] -name = "nancy" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = ".NET" -webserver = "Kestrel" -versus = "aspcore-mono" - -[netcore] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = ".NET" -webserver = "Kestrel" -versus = "aspcore" diff --git a/frameworks/CSharp/nancy/nancy-netcore.dockerfile b/frameworks/CSharp/nancy/nancy-netcore.dockerfile deleted file mode 100644 index 002cbe44076..00000000000 --- a/frameworks/CSharp/nancy/nancy-netcore.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build -WORKDIR /source -COPY src . -RUN dotnet publish -c Release -f net7.0 -o /app - -FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime -# Full PGO -ENV DOTNET_TieredPGO 1 -ENV DOTNET_TC_QuickJitForLoops 1 -ENV DOTNET_ReadyToRun 0 - -ENV ASPNETCORE_URLS http://+:8080 -WORKDIR /app -COPY --from=build /app . - -EXPOSE 8080 - -ENTRYPOINT ["dotnet", "NancyBenchmark.dll"] diff --git a/frameworks/CSharp/nancy/nancy.dockerfile b/frameworks/CSharp/nancy/nancy.dockerfile deleted file mode 100644 index f7d4515e0bb..00000000000 --- a/frameworks/CSharp/nancy/nancy.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build -WORKDIR /source -COPY src . -RUN dotnet publish -c Release -f net471 -o /app - -FROM mono:6.8 AS runtime -WORKDIR /app -COPY --from=build /app . -ENV ASPNETCORE_URLS http://+:8080 - -EXPOSE 8080 - -ENTRYPOINT ["mono", "--server", "--gc=sgen", "--gc-params=mode=throughput", "NancyBenchmark.exe"] diff --git a/frameworks/CSharp/nancy/src/AppConfiguration.cs b/frameworks/CSharp/nancy/src/AppConfiguration.cs deleted file mode 100644 index ecebdb1fb70..00000000000 --- a/frameworks/CSharp/nancy/src/AppConfiguration.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Nancy.Benchmark -{ - public class AppConfiguration : IAppConfiguration - { - public string ConnectionString { get; set; } - } -} diff --git a/frameworks/CSharp/nancy/src/Bootstrapper.cs b/frameworks/CSharp/nancy/src/Bootstrapper.cs deleted file mode 100644 index 40429fcb486..00000000000 --- a/frameworks/CSharp/nancy/src/Bootstrapper.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Nancy.Benchmark -{ - using Nancy.TinyIoc; - - public class Bootstrapper : DefaultNancyBootstrapper - { - private readonly IAppConfiguration appConfig; - - public Bootstrapper() - { - } - - public Bootstrapper(IAppConfiguration appConfig) - { - this.appConfig = appConfig; - } - - protected override void ConfigureApplicationContainer(TinyIoCContainer container) - { - base.ConfigureApplicationContainer(container); - - container.Register(appConfig); - } - } -} diff --git a/frameworks/CSharp/nancy/src/DbModule.cs b/frameworks/CSharp/nancy/src/DbModule.cs deleted file mode 100644 index 2795117ddc4..00000000000 --- a/frameworks/CSharp/nancy/src/DbModule.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Nancy.Benchmark -{ - using System; - using System.Data; - using System.Threading.Tasks; - using Dapper; - using MySqlConnector; - using Nancy; - - public class DbModule : NancyModule - { - private readonly string ConnectionString; - - /** - * NOTE: - * Return a single World objects as JSON, selected randomly from the World - * table. Assume the table has 10,000 rows. - */ - public DbModule(IAppConfiguration appConfig) : base("/db") - { - ConnectionString = appConfig.ConnectionString; - - Get("/{queries?1}", async args => - { - var random = new Random(); - using (var db = new MySqlConnection(ConnectionString)) - { - db.Open(); - return Response.AsJson(await GetRandomWorld(db, random)); - } - }); - } - - private Task GetRandomWorld(IDbConnection db, Random random) - { - var id = random.Next(1, 10001); - return db.QueryFirstOrDefaultAsync("SELECT id, randomNumber FROM world WHERE id = @id", new { id }); - } - } - - public class World - { - public int id { get; set; } - public int randomNumber { get; set; } - } -} diff --git a/frameworks/CSharp/nancy/src/IAppConfiguration.cs b/frameworks/CSharp/nancy/src/IAppConfiguration.cs deleted file mode 100644 index 3d1f4e78965..00000000000 --- a/frameworks/CSharp/nancy/src/IAppConfiguration.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Nancy.Benchmark -{ - public interface IAppConfiguration - { - string ConnectionString { get; } - } -} diff --git a/frameworks/CSharp/nancy/src/JsonModule.cs b/frameworks/CSharp/nancy/src/JsonModule.cs deleted file mode 100644 index 7799b6c2714..00000000000 --- a/frameworks/CSharp/nancy/src/JsonModule.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Nancy.Benchmark -{ - public class JsonModule : NancyModule - { - public JsonModule() : base("/json") - { - Get("/", args => - { - return Response.AsJson(new { message = "Hello, World!" }); - }); - } - } -} diff --git a/frameworks/CSharp/nancy/src/NancyBenchmark.csproj b/frameworks/CSharp/nancy/src/NancyBenchmark.csproj deleted file mode 100644 index b99adc67119..00000000000 --- a/frameworks/CSharp/nancy/src/NancyBenchmark.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - net7.0;net471 - Exe - - - - linux-x64 - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frameworks/CSharp/nancy/src/NancyBenchmark.sln b/frameworks/CSharp/nancy/src/NancyBenchmark.sln deleted file mode 100644 index cea30172147..00000000000 --- a/frameworks/CSharp/nancy/src/NancyBenchmark.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27705.2000 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NancyBenchmark", "NancyBenchmark.csproj", "{5F21E79A-D31E-4DAE-A459-76ED26A9AC47}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5F21E79A-D31E-4DAE-A459-76ED26A9AC47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F21E79A-D31E-4DAE-A459-76ED26A9AC47}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F21E79A-D31E-4DAE-A459-76ED26A9AC47}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F21E79A-D31E-4DAE-A459-76ED26A9AC47}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9818363B-8BDB-4E5E-960F-DAAD6C0D171D} - EndGlobalSection -EndGlobal diff --git a/frameworks/CSharp/nancy/src/PlainModule.cs b/frameworks/CSharp/nancy/src/PlainModule.cs deleted file mode 100644 index 17b98815683..00000000000 --- a/frameworks/CSharp/nancy/src/PlainModule.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Nancy.Benchmark -{ - public class PlainModule : NancyModule - { - public PlainModule() : base("plaintext") - { - Get("/", args => - { - return Response.AsText("Hello, World!"); - }); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/nancy/src/Program.cs b/frameworks/CSharp/nancy/src/Program.cs deleted file mode 100644 index b6923bfc660..00000000000 --- a/frameworks/CSharp/nancy/src/Program.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Nancy.Benchmark -{ - using System.IO; - using Microsoft.AspNetCore.Hosting; - using Microsoft.Extensions.Configuration; - - public class Program - { - public static void Main(string[] args) - { - var config = new ConfigurationBuilder() - .AddJsonFile("hosting.json", optional: true) - .AddEnvironmentVariables(prefix: "ASPNETCORE_") - .AddCommandLine(args) - .Build(); - - var webHost = new WebHostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseConfiguration(config) - .UseStartup() - .UseKestrel(o => - { - o.AllowSynchronousIO = true; - }) - .Build(); - - webHost.Run(); - } - } -} diff --git a/frameworks/CSharp/nancy/src/QueryModule.cs b/frameworks/CSharp/nancy/src/QueryModule.cs deleted file mode 100644 index 764c2df862a..00000000000 --- a/frameworks/CSharp/nancy/src/QueryModule.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace Nancy.Benchmark -{ - using System; - using System.Data; - using System.Threading.Tasks; - using Dapper; - using MySqlConnector; - using Nancy; - - public class QueryModule : NancyModule - { - private readonly string ConnectionString; - - /** - * Query: - * Return a list of World objects as JSON, selected randomly from the World - * table. Assume the table has 10,000 rows. - */ - public QueryModule(IAppConfiguration appConfig) : base("/queries") - { - ConnectionString = appConfig.ConnectionString; - - Get("/{queries?1}", async args => - { - if (!int.TryParse((string)args.queries, out var queries) || queries < 1) - { - queries = 1; - } - else if (queries > 500) - { - queries = 500; - } - - var random = new Random(); - using (var db = new MySqlConnection(ConnectionString)) - { - db.Open(); - - // NOTE: Experiment with running the DB requests in parallel, on both Mono and Windows CLRs. - var worlds = new World[queries]; - - for (int i = 0; i < worlds.Length; ++i) - { - worlds[i] = await GetRandomWorld(db, random); - } - return Response.AsJson( worlds ); - } - }); - - Get("/{name}", async args => - { - if (!int.TryParse((string)args.name, out var queries) || queries < 1) - { - queries = 1; - } - else if (queries > 500) - { - queries = 500; - } - - var random = new Random(); - using (var db = new MySqlConnection(ConnectionString)) - { - db.Open(); - - // NOTE: Experiment with running the DB requests in parallel, on both Mono and Windows CLRs. - var worlds = new World[queries]; - - for (int i = 0; i < worlds.Length; ++i) - { - worlds[i] = await GetRandomWorld(db, random); - } - return Response.AsJson( worlds ); - } - - }); - } - - private Task GetRandomWorld(IDbConnection db, Random random) - { - var id = random.Next(1, 10001); - return db.QueryFirstOrDefaultAsync("SELECT id, randomNumber FROM world WHERE id = @id", new { id }); - } - } - -} \ No newline at end of file diff --git a/frameworks/CSharp/nancy/src/Startup.cs b/frameworks/CSharp/nancy/src/Startup.cs deleted file mode 100644 index c33e6955aee..00000000000 --- a/frameworks/CSharp/nancy/src/Startup.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Nancy.Benchmark -{ - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Hosting; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Nancy.Owin; - - public class Startup - { - public IConfiguration Configuration { get; } - -#if NETFRAMEWORK - public Startup(IHostingEnvironment env) -#elif NETCOREAPP - public Startup(IWebHostEnvironment env) -#endif - { - var builder = new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .SetBasePath(env.ContentRootPath); - - Configuration = builder.Build(); - } - - public void Configure(IApplicationBuilder app) - { - var appConfig = new AppConfiguration(); - ConfigurationBinder.Bind(Configuration, appConfig); - - app.UseOwin(x => x.UseNancy(opt => opt.Bootstrapper = new Bootstrapper(appConfig))); - } - } -} diff --git a/frameworks/CSharp/nancy/src/appsettings.json b/frameworks/CSharp/nancy/src/appsettings.json deleted file mode 100644 index 79d9134a159..00000000000 --- a/frameworks/CSharp/nancy/src/appsettings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;SslMode=None;ConnectionReset=false;ConnectionIdlePingTime=900;ConnectionIdleTimeout=0", - "Database": "mysql" -} diff --git a/frameworks/CSharp/touchsocket/benchmark_config.json b/frameworks/CSharp/touchsocket/benchmark_config.json index 2a6d6c27e98..98c0dff5670 100644 --- a/frameworks/CSharp/touchsocket/benchmark_config.json +++ b/frameworks/CSharp/touchsocket/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "touchsocket", + "maintainers": ["rrqm"], "tests": [ { "default": { @@ -82,7 +83,7 @@ "plaintext_url": "/plaintext", "json_url": "/json", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "touchsocket.httpplatform", diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs index de84e8b6028..4febee60946 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs @@ -25,18 +25,18 @@ await service.SetupAsync(new TouchSocketConfig() pool: MemoryPool.Shared, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: 1024 * 1024, - resumeWriterThreshold: 1024 * 512, - minimumSegmentSize: -1, + pauseWriterThreshold: 2 * 1024 * 1024, + resumeWriterThreshold: 1024 * 1024, + minimumSegmentSize: 8192, useSynchronizationContext: false); options.SendPipeOptions = new PipeOptions( pool: MemoryPool.Shared, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: 64 * 1024, - resumeWriterThreshold: 32 * 1024, - minimumSegmentSize: -1, + pauseWriterThreshold: 128 * 1024, + resumeWriterThreshold: 64 * 1024, + minimumSegmentSize: 8192, useSynchronizationContext: false); }) .ConfigureContainer(a => diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj index c694366fc8d..16b0c5ee1e1 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj @@ -5,10 +5,11 @@ enable Exe enable + true - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs index 9f0049fc54d..f54db4599b5 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs @@ -20,7 +20,7 @@ namespace TouchSocketHttpPlatform; internal static class DateHeader { private const int dateTimeRLength = 29; - private const int prefixLength = 6; // "Date: ".Length is 6 in bytes for ASCII + private const int prefixLength = 8; // "\r\nDate: ".Length is 8 in bytes for ASCII private const int suffixIndex = dateTimeRLength + prefixLength; // Wed, 14 Mar 2018 14:20:00 GMT @@ -35,7 +35,7 @@ internal static class DateHeader static DateHeader() { - var utf8 = "Date: "u8; + var utf8 = "\r\nDate: "u8; utf8.CopyTo(s_headerBytesMaster); utf8.CopyTo(s_headerBytesScratch); diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs index 788205e483c..500b940e71f 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs @@ -52,13 +52,13 @@ internal sealed class MyTcpSessionClientBase : TcpSessionClient "HTTP/1.1 200 OK\r\n"u8 + "Server: T\r\n"u8 + "Content-Type: text/plain\r\n"u8 + - "Content-Length: 13\r\n"u8; + "Content-Length: 13"u8; private static ReadOnlySpan JsonPreamble => "HTTP/1.1 200 OK\r\n"u8 + "Server: T\r\n"u8 + "Content-Type: application/json\r\n"u8 + - "Content-Length: 27\r\n"u8; + "Content-Length: 27"u8; protected override async Task ReceiveLoopAsync(ITransport transport) { @@ -119,9 +119,11 @@ private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter wr while (!seqReader.End) { var startConsumed = seqReader.Consumed; + var startPosition = seqReader.Position; if (!TryReadLine(ref seqReader, out var requestLineLength)) { + seqReader.Rewind(seqReader.Consumed - startConsumed); break; } @@ -152,6 +154,7 @@ private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter wr if (!headersComplete) { + seqReader.Rewind(seqReader.Consumed - startConsumed); break; } @@ -187,28 +190,30 @@ private static void WriteResponseSync(PipeWriter writer, RouteType routeType) [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private static bool TryReadLine(ref SequenceReader reader, out long length) { - if (reader.TryAdvanceTo((byte)'\r', advancePastDelimiter: false)) + var startPosition = reader.Position; + var startConsumed = reader.Consumed; + + while (reader.TryAdvanceTo((byte)'\r', advancePastDelimiter: false)) { - var start = reader.Consumed; - if (!reader.TryPeek(1, out var next)) { + reader.Rewind(reader.Consumed - startConsumed); length = 0; return false; } if (next == '\n') { - var lineLength = reader.Consumed; + var lineLength = reader.Consumed - startConsumed; reader.Advance(2); - length = lineLength - start; + length = lineLength; return true; } reader.Advance(1); - return TryReadLine(ref reader, out length); } + reader.Rewind(reader.Consumed - startConsumed); length = 0; return false; } diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs index 7957bcd8c22..07a6b2ec99f 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs @@ -30,21 +30,21 @@ await server.SetupAsync(new TouchSocketConfig() options.BufferOnDemand = false; options.ReceivePipeOptions = new PipeOptions( - pool: MemoryPool.Shared, - readerScheduler: PipeScheduler.ThreadPool, - writerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: 1024 * 1024, - resumeWriterThreshold: 1024 * 512, - minimumSegmentSize: -1, - useSynchronizationContext: false); + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 2 * 1024 * 1024, + resumeWriterThreshold: 1024 * 1024, + minimumSegmentSize: 8192, + useSynchronizationContext: false); options.SendPipeOptions = new PipeOptions( pool: MemoryPool.Shared, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: 64 * 1024, - resumeWriterThreshold: 32 * 1024, - minimumSegmentSize: -1, + pauseWriterThreshold: 128 * 1024, + resumeWriterThreshold: 64 * 1024, + minimumSegmentSize: 8192, useSynchronizationContext: false); }) .ConfigureContainer(a => diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj index 25feeea4984..690ec6071a2 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj @@ -5,9 +5,10 @@ net10.0 enable enable + true - + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs index 1dc198dc165..a8d535a670f 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs @@ -25,21 +25,21 @@ public static void Main(string[] args) options.BufferOnDemand = false; options.ReceivePipeOptions = new PipeOptions( - pool: MemoryPool.Shared, - readerScheduler: PipeScheduler.ThreadPool, - writerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: 1024 * 1024, - resumeWriterThreshold: 1024 * 512, - minimumSegmentSize: -1, - useSynchronizationContext: false); + pool: MemoryPool.Shared, + readerScheduler: PipeScheduler.ThreadPool, + writerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: 2 * 1024 * 1024, + resumeWriterThreshold: 1024 * 1024, + minimumSegmentSize: 8192, + useSynchronizationContext: false); options.SendPipeOptions = new PipeOptions( pool: MemoryPool.Shared, readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: 64 * 1024, - resumeWriterThreshold: 32 * 1024, - minimumSegmentSize: -1, + pauseWriterThreshold: 128 * 1024, + resumeWriterThreshold: 64 * 1024, + minimumSegmentSize: 8192, useSynchronizationContext: false); }) .ConfigureContainer(a => diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj index 3b3d56852ce..dba68f5af5f 100644 --- a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj @@ -4,12 +4,13 @@ net10.0 enable enable + true dotnet-WorkerService1-19b37b17-6043-4334-ad9a-9e0e3c670da3 - - + + diff --git a/frameworks/CSharp/watson/benchmark_config.json b/frameworks/CSharp/watson/benchmark_config.json index 6017f614566..d6f8c86dece 100644 --- a/frameworks/CSharp/watson/benchmark_config.json +++ b/frameworks/CSharp/watson/benchmark_config.json @@ -16,7 +16,8 @@ "os": "Linux", "database_os": "Linux", "display_name": "Watson Webserver", - "notes": "" + "notes": "", + "tags": ["broken"] } }] } diff --git a/frameworks/CSharp/wiredio/UnhGHttp/Program.cs b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs deleted file mode 100644 index 03d8a523ff3..00000000000 --- a/frameworks/CSharp/wiredio/UnhGHttp/Program.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Text.Json; -using GenHTTP.Api.Protocol; -using GenHTTP.Modules.IO; -using GenHTTP.Modules.Layouting; -using GenHTTP.Modules.Layouting.Provider; -using Unhinged; -using Unhinged.GenHttp.Experimental; - -internal class Program -{ - public static void Main(string[] args) - { - var builder = UnhingedEngine - .CreateBuilder() - .SetNWorkersSolver(() => Environment.ProcessorCount) - .SetBacklog(16384) - .SetMaxEventsPerWake(512) - .SetMaxNumberConnectionsPerWorker(512) - .SetPort(8080) - .SetSlabSizes(32 * 1024, 16 * 1024) - .Map(CreateLayoutBuilder()); - - var engine = builder.Build(); - engine.Run(); - } - - private static LayoutBuilder CreateLayoutBuilder() => - Layout - .Create() - .Add("/plaintext", Content.From(Resource.FromString("Hello, World!"))) - - .Add("/json", Content.From( - Resource.FromString(JsonSerializer.Serialize(new JsonMessage { message = "Hello, World!" })) - .Type(new FlexibleContentType("application/json")))); -} - -public class JsonMessage -{ - public string message { get; set; } -} \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj b/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj deleted file mode 100644 index 09308ff4747..00000000000 --- a/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - Exe - net9.0 - enable - enable - - true - true - true - true - - linux-musl-x64 - - - - - - - - - diff --git a/frameworks/CSharp/wiredio/benchmark_config.json b/frameworks/CSharp/wiredio/benchmark_config.json index 2d9ebf4896f..a2e7a3df977 100644 --- a/frameworks/CSharp/wiredio/benchmark_config.json +++ b/frameworks/CSharp/wiredio/benchmark_config.json @@ -24,7 +24,7 @@ "plaintext_url": "/plaintext", "json_url": "/json", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Micro", "database": "None", "framework": "Unhinged", @@ -41,7 +41,7 @@ "plaintext_url": "/plaintext", "json_url": "/json", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Micro", "database": "None", "framework": "Unhinged", @@ -53,23 +53,6 @@ "database_os": "Linux", "display_name": "Unhinged [p]", "notes": "epoll" - }, - "gen": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "None", - "framework": "GenHttp", - "language": "C#", - "orm": "None", - "platform": ".NET", - "webserver": "Unhinged", - "os": "Linux", - "database_os": "Linux", - "display_name": "genhttp [Unhinged]", - "notes": "Adapter" } } ] diff --git a/frameworks/CSharp/wiredio/config.toml b/frameworks/CSharp/wiredio/config.toml index 0b973f1f1fb..c0e5b1efa44 100644 --- a/frameworks/CSharp/wiredio/config.toml +++ b/frameworks/CSharp/wiredio/config.toml @@ -36,15 +36,3 @@ orm = "None" platform = ".NET" webserver = "Unhinged" versus = "None" - -[gen] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -os = "Linux" -database_os = "Linux" -orm = "None" -platform = ".NET" -webserver = "Unhinged" -versus = "None" \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/wiredio-gen.dockerfile b/frameworks/CSharp/wiredio/wiredio-gen.dockerfile deleted file mode 100644 index 5436527f964..00000000000 --- a/frameworks/CSharp/wiredio/wiredio-gen.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build -WORKDIR /source - -# copy csproj and restore as distinct layers -COPY UnhGHttp/*.csproj . -RUN dotnet restore -r linux-musl-x64 - -# copy and publish app and libraries -COPY UnhGHttp/ . -RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained - -# final stage/image -FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine - -ENV DOTNET_GCDynamicAdaptationMode=0 -ENV DOTNET_ReadyToRun=0 -ENV DOTNET_HillClimbing_Disable=1 - -WORKDIR /app -COPY --from=build /app . - -ENTRYPOINT ["./UnhGHttp"] - -EXPOSE 8080 diff --git a/frameworks/Clojure/compojure/README.md b/frameworks/Clojure/compojure/README.md index f88d93f68e8..7891dd06b33 100644 --- a/frameworks/Clojure/compojure/README.md +++ b/frameworks/Clojure/compojure/README.md @@ -14,7 +14,6 @@ This is the Compojure portion of a [benchmarking test suite](../) comparing a va The dependencies are documented in [project.clj](hello/project.clj), but the main ones are: -* [Clojure 1.8.0](http://clojure.org/) -* [Compojure 1.4.0](https://github.com/weavejester/compojure) -* [Ring-JSON 0.4.0](https://github.com/ring-clojure/ring-json), which in turn uses [Cheshire](https://github.com/dakrone/cheshire), which in turn uses [Jackson](http://jackson.codehaus.org/) -* [Korma 0.4.2](http://sqlkorma.com/) +* [Clojure 1.12.4](http://clojure.org/) +* [Compojure 1.7.2](https://github.com/weavejester/compojure) +* [Ring-JSON 0.5.1](https://github.com/ring-clojure/ring-json), which in turn uses [Cheshire](https://github.com/dakrone/cheshire), which in turn uses [Jackson](http://jackson.codehaus.org/) diff --git a/frameworks/Clojure/compojure/benchmark_config.json b/frameworks/Clojure/compojure/benchmark_config.json index 70ed3a5c7b8..787f76d8400 100644 --- a/frameworks/Clojure/compojure/benchmark_config.json +++ b/frameworks/Clojure/compojure/benchmark_config.json @@ -23,27 +23,6 @@ "display_name": "compojure", "notes": "", "versus": "servlet" - }, - "raw": { - "db_url": "/raw/db", - "query_url": "/raw/queries/", - "update_url": "/raw/updates/", - "fortune_url": "/raw/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "compojure", - "language": "Clojure", - "flavor": "None", - "orm": "Raw", - "platform": "Servlet", - "webserver": "Resin", - "os": "Linux", - "database_os": "Linux", - "display_name": "compojure-raw", - "notes": "", - "versus": "servlet" } }] } diff --git a/frameworks/Clojure/compojure/compojure-raw.dockerfile b/frameworks/Clojure/compojure/compojure-raw.dockerfile deleted file mode 100644 index 2a3a4758188..00000000000 --- a/frameworks/Clojure/compojure/compojure-raw.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM clojure:openjdk-11-lein-2.9.1 as lein -WORKDIR /compojure -COPY src src -COPY project.clj project.clj -RUN lein ring uberwar - -FROM openjdk:11.0.3-jdk-stretch -WORKDIR /resin -RUN curl -sL http://caucho.com/download/resin-4.0.61.tar.gz | tar xz --strip-components=1 -RUN rm -rf webapps/* -COPY --from=lein /compojure/target/hello-compojure-standalone.war webapps/ROOT.war -COPY resin.xml conf/resin.xml - -EXPOSE 8080 - -CMD ["java", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "lib/resin.jar", "console"] diff --git a/frameworks/Clojure/compojure/compojure.dockerfile b/frameworks/Clojure/compojure/compojure.dockerfile index 5205fcb18e6..8fc5cb7f961 100644 --- a/frameworks/Clojure/compojure/compojure.dockerfile +++ b/frameworks/Clojure/compojure/compojure.dockerfile @@ -1,16 +1,19 @@ -FROM clojure:openjdk-11-lein-2.9.1 as lein +FROM clojure:lein as lein WORKDIR /compojure COPY src src COPY project.clj project.clj RUN lein ring uberwar -FROM openjdk:11.0.3-jdk-stretch +FROM curlimages/curl:8.17.0 as resin-builder +USER root WORKDIR /resin -RUN curl -sL http://caucho.com/download/resin-4.0.61.tar.gz | tar xz --strip-components=1 +RUN curl -sL http://caucho.com/download/resin-4.0.66.tar.gz | tar xz --strip-components=1 RUN rm -rf webapps/* COPY --from=lein /compojure/target/hello-compojure-standalone.war webapps/ROOT.war -COPY resin.xml conf/resin.xml +FROM amazoncorretto:25 +WORKDIR /resin +COPY --from=resin-builder /resin . +COPY resin.xml conf/resin.xml EXPOSE 8080 - -CMD ["java", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true","-jar", "lib/resin.jar", "console"] +CMD ["java", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "lib/resin.jar", "console"] \ No newline at end of file diff --git a/frameworks/Clojure/compojure/config.toml b/frameworks/Clojure/compojure/config.toml index f854ff81879..2216d70801e 100644 --- a/frameworks/Clojure/compojure/config.toml +++ b/frameworks/Clojure/compojure/config.toml @@ -17,18 +17,3 @@ orm = "Micro" platform = "Servlet" webserver = "Resin" versus = "servlet" - -[raw] -urls.db = "/raw/db" -urls.query = "/raw/queries/" -urls.update = "/raw/updates/" -urls.fortune = "/raw/fortunes" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Servlet" -webserver = "Resin" -versus = "servlet" diff --git a/frameworks/Clojure/compojure/project.clj b/frameworks/Clojure/compojure/project.clj index 60abf030167..bf829e23ce5 100644 --- a/frameworks/Clojure/compojure/project.clj +++ b/frameworks/Clojure/compojure/project.clj @@ -2,15 +2,14 @@ :description "FrameworkBenchmarks test implementations" :url "http://localhost:3000/" :min-lein-version "2.0.0" - :dependencies [[org.clojure/clojure "1.8.0"] - [compojure "1.4.0"] - [ring/ring-json "0.4.0"] - [korma "0.5.0-RC1"] + :dependencies [[org.clojure/clojure "1.12.4"] + [compojure "1.7.2"] + [ring/ring-json "0.5.1"] [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]] - [mysql/mysql-connector-java "8.0.18"] - [com.mchange/c3p0 "0.9.5.4"] - [org.clojure/java.jdbc "0.7.9"] - [hikari-cp "1.8.3"] + [com.mysql/mysql-connector-j "9.6.0"] + [org.clojars.jj/majavat "1.19.0"] + [com.github.seancorfield/next.jdbc "1.3.1093"] + [hikari-cp "4.0.0"] [hiccup "1.0.5"]] :repositories {"Sonatype releases" "https://oss.sonatype.org/content/repositories/releases/"} :plugins [[lein-ring "0.12.5"] diff --git a/frameworks/Clojure/compojure/src/hello/handler.clj b/frameworks/Clojure/compojure/src/hello/handler.clj index 70971dc2f6e..869a11fd3f2 100644 --- a/frameworks/Clojure/compojure/src/hello/handler.clj +++ b/frameworks/Clojure/compojure/src/hello/handler.clj @@ -1,165 +1,103 @@ (ns hello.handler - (:use compojure.core - ring.middleware.content-type - ring.middleware.json - korma.db - korma.core - hiccup.core - hiccup.util - hiccup.page) - (:require [compojure.handler :as handler] + (:require [next.jdbc :as jdbc] + [next.jdbc.result-set :as rs] + [compojure.core :refer [GET defroutes]] [compojure.route :as route] - [ring.util.response :as ring-resp] - [clojure.java.jdbc :as jdbc] - [hikari-cp.core :refer :all])) + [hiccup.page :refer [html5]] + [hiccup.util :refer [escape-html]] + [hikari-cp.core :refer :all] + [ring.middleware.json :as json-middleware] + [ring.util.response :as ring-resp])) (defn sanitize-queries-param "Sanitizes the `queries` parameter. Clamps the value between 1 and 500. Invalid (string) values become 1." [queries] (let [n (try (Integer/parseInt queries) - (catch Exception e 1))] ; default to 1 on parse failure + (catch Exception _ 1))] (cond (< n 1) 1 (> n 500) 500 :else n))) -;; MySQL database connection -(defdb db-mysql - (mysql { - :classname "com.mysql.cj.jdbc.Driver" - :subprotocol "mysql" - :subname "//tfb-database:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts=true&cacheRSMetadata=true&useSSL=false" - :user "benchmarkdbuser" - :password "benchmarkdbpass" - ;;OPTIONAL KEYS - :delimiters "" ;; remove delimiters - :maximum-pool-size 512})) - -;; Create HikariCP-pooled "raw" jdbc data source (defn make-hikari-data-source [] - (make-datasource {:auto-commit true - :read-only false - :connection-timeout 30000 - :validation-timeout 5000 - :idle-timeout 600000 - :max-lifetime 1800000 - :minimum-idle 10 - :maximum-pool-size 512 - :pool-name "db-pool" - :driver-class-name "com.mysql.cj.jdbc.Driver" - :datasource-class-name "com.mysql.cj.jdbc.MysqlDataSource" - :jdbc-url "jdbc:mysql://tfb-database:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts=true&cacheRSMetadata=true&useSSL=false" - :username "benchmarkdbuser" - :password "benchmarkdbpass" - :register-mbeans false})) + (make-datasource { + :idle-timeout 15000 + :max-lifetime 60000 + :minimum-idle 0 + :maximum-pool-size 1024 + :pool-name "db-pool" + :driver-class-name "com.mysql.cj.jdbc.Driver" + :jdbc-url "jdbc:mysql://tfb-database:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts=true&cacheRSMetadata=true&useSSL=false" + :username "benchmarkdbuser" + :password "benchmarkdbpass" + :register-mbeans false})) -;; Reuse a single HikariCP-pooled data source (def memoize-hikari-data-source (memoize make-hikari-data-source)) -;; Get a HikariCP-pooled "raw" jdbc connection -(defn db-mysql-raw [] {:datasource (memoize-hikari-data-source)}) +(defn db-mysql [] (memoize-hikari-data-source)) -;; Set up entity World and the database representation -(defentity world - (pk :id) - (table :world) - (entity-fields :id :randomNumber) ; Default fields for select - (database db-mysql)) -(defn get-random-world-korma - "Query a random World record from the database" - [] - (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000 - (select world - (where {:id id })))) - -(defn run-queries - "Run query repeatedly, return an array" - [queries] - (flatten ; Make it a list of maps - (take queries ; Number of queries to run - (repeatedly get-random-world-korma)))) - -(defn get-random-world-raw +(defn get-random-world "Query a random World record from the database" [] (let [id (inc (rand-int 9999))] - (jdbc/query (db-mysql-raw) [(str "select * from world where id = ?") id]))) + (jdbc/execute! (db-mysql) + ["select * from world where id = ?" id] + {:builder-fn rs/as-unqualified-lower-maps}))) -(defn run-queries-raw +(defn run-queries "Run query repeatedly, return an array" [queries] - (flatten ; Make it a list of maps + (flatten (take queries - (repeatedly get-random-world-raw)))) + (repeatedly get-random-world)))) -;; Set up entity Fortune and the database representation -(defentity fortune - (pk :id) - (table :fortune) - (entity-fields :id :message) - (database db-mysql)) - -(defn get-all-fortunes-korma - "Query all Fortune records from the database using Korma." - [] - (select fortune - (fields :id :message))) -(defn get-all-fortunes-raw - "Query all Fortune records from the database using JDBC." +(defn get-all-fortunes + "Query all Fortune records from the database using next.jdbc." [] - (jdbc/query (db-mysql-raw) [(str "select * from fortune")])) + (jdbc/execute! (db-mysql) + ["select * from fortune"] + {:builder-fn rs/as-unqualified-lower-maps})) (defn get-fortunes "Fetch the full list of Fortunes from the database, sort them by the fortune message text, and then return the results." [query-function] (sort-by #(:message %) - (conj - (query-function) - { :id 0 :message "Additional fortune added at request time." }))) + (conj + (query-function) + {:id 0 :message "Additional fortune added at request time."}))) (defn fortunes-hiccup "Render the given fortunes to simple HTML using Hiccup." [fortunes] (html5 - [:head - [:title "Fortunes"]] - [:body - [:table - [:tr - [:th "id"] - [:th "message"]] - (for [x fortunes] - [:tr - [:td (:id x)] - [:td (escape-html (:message x))]]) - ]])) - -(defn update-and-persist-korma - "Using Korma: Changes the :randomNumber of a number of world entities. + [:head + [:title "Fortunes"]] + [:body + [:table + [:tr + [:th "id"] + [:th "message"]] + (for [x fortunes] + [:tr + [:td (:id x)] + [:td (escape-html (:message x))]]) + ]])) + + +(defn update-and-persist + "Using next.jdbc: Changes the :randomNumber of a number of world entities. Persists the changes to sql then returns the updated entities" [queries] - (let [results (map #(assoc % :randomNumber (inc (rand-int 9999))) (run-queries queries))] - (doseq [{:keys [id randomNumber]} results] - (update world - (set-fields {:randomNumber randomNumber}) - (where {:id id}))) - results)) - -(defn update-and-persist-raw - "Using JDBC: Changes the :randomNumber of a number of world entities. - Persists the changes to sql then returns the updated entities" - [queries] - (let [world (map #(assoc % :randomnumber (inc (rand-int 9999))) (run-queries-raw queries))] + (let [world (map #(assoc % :randomnumber (inc (rand-int 9999))) (run-queries queries))] (doseq [{:keys [id randomnumber]} world] - (jdbc/update! - (db-mysql-raw) - :world {:randomnumber randomnumber} - ["id = ?" id])) + (jdbc/execute-one! + (db-mysql) + ["UPDATE world SET randomnumber = ? WHERE id = ?" randomnumber id])) world)) (defn json-serialization @@ -170,47 +108,24 @@ (defn single-query-test "Test 2: Single database query" [] - (ring-resp/response (first (run-queries 1)))) - -(defn multiple-queries-test - "Test 3: Multiple database queries" - [queries] - (-> queries - (sanitize-queries-param) - (run-queries) - (ring-resp/response))) - -(defn single-query-test-raw - "Test 2: Single database query (raw)" - [] (-> 1 - (run-queries-raw) + (run-queries) (first) (ring-resp/response))) -(defn multiple-queries-test-raw - "Test 3: Multiple database queries (raw)" +(defn multiple-queries-test + "Test 3: Multiple database queries" [queries] (-> queries (sanitize-queries-param) - (run-queries-raw) + (run-queries) (ring-resp/response))) (defn fortune-test "Test 4: Fortunes" [] (-> - (get-fortunes get-all-fortunes-korma) - (fortunes-hiccup) - (ring-resp/response) - (ring-resp/content-type "text/html") - (ring-resp/charset "utf-8"))) - -(defn fortune-test-raw - "Test 4: Fortunes Raw" - [] - (-> - (get-fortunes get-all-fortunes-raw) + (get-fortunes get-all-fortunes) (fortunes-hiccup) (ring-resp/response) (ring-resp/content-type "text/html") @@ -221,15 +136,7 @@ [queries] (-> queries (sanitize-queries-param) - (update-and-persist-korma) - (ring-resp/response))) - -(defn db-updates-raw - "Test 5: Database updates Raw" - [queries] - (-> queries - (sanitize-queries-param) - (update-and-persist-raw) + (update-and-persist) (ring-resp/response))) (def plaintext @@ -240,24 +147,18 @@ ;; Define route handlers (defroutes app-routes - (GET "/" [] "Hello, World!") - (GET "/plaintext" [] plaintext) - (GET "/json" [] (json-serialization)) - (GET "/db" [] (single-query-test)) - (GET "/queries/:queries" [queries] (multiple-queries-test queries)) - (GET "/queries/" [] (multiple-queries-test 1)) ; When param is omitted - (GET "/fortunes" [] (fortune-test)) - (GET "/updates/:queries" [queries] (db-updates queries)) - (GET "/updates/" [] (db-updates 1)) ; When param is omitted - (GET "/raw/db" [] (single-query-test-raw)) - (GET "/raw/queries/:queries" [queries] (multiple-queries-test-raw queries)) - (GET "/raw/queries/" [] (multiple-queries-test-raw 1)) ; When param is omitted - (GET "/raw/fortunes" [] (fortune-test-raw)) - (GET "/raw/updates/:queries" [queries] (db-updates-raw queries)) - (GET "/raw/updates/" [] (db-updates-raw 1)) ; When param is omitted - (route/not-found "Not Found")) + (GET "/" [] "Hello, World!") + (GET "/plaintext" [] plaintext) + (GET "/json" [] (json-serialization)) + (GET "/db" [] (single-query-test)) + (GET "/queries/:queries" [queries] (multiple-queries-test queries)) + (GET "/queries/" [] (multiple-queries-test 1)) + (GET "/fortunes" [] (fortune-test)) + (GET "/updates/:queries" [queries] (db-updates queries)) + (GET "/updates/" [] (db-updates 1)) + (route/not-found "Not Found")) (def app "Format responses as JSON" (-> app-routes - (wrap-json-response))) + (json-middleware/wrap-json-response))) \ No newline at end of file diff --git a/frameworks/Clojure/duct/benchmark_config.json b/frameworks/Clojure/duct/benchmark_config.json index 9f52c5033c4..fbc345e0a8e 100755 --- a/frameworks/Clojure/duct/benchmark_config.json +++ b/frameworks/Clojure/duct/benchmark_config.json @@ -22,7 +22,7 @@ "database_os": "Linux", "display_name": "duct", "notes": "", - "versus": "None" + "versus": "" }, "mongodb": { "db_url": "/db-mongo", @@ -65,7 +65,7 @@ "database_os": "Linux", "display_name": "duct-httpkit", "notes": "", - "versus": "None" + "versus": "duct" }, "aleph": { "json_url": "/json", @@ -87,7 +87,7 @@ "database_os": "Linux", "display_name": "duct-aleph", "notes": "", - "versus": "None" + "versus": "duct" }, "immutant": { "json_url": "/json", diff --git a/frameworks/Clojure/duct/config.toml b/frameworks/Clojure/duct/config.toml index 436afd54d9b..50069169363 100644 --- a/frameworks/Clojure/duct/config.toml +++ b/frameworks/Clojure/duct/config.toml @@ -45,7 +45,7 @@ os = "Linux" orm = "Raw" platform = "Ring" webserver = "None" -versus = "None" +versus = "duct" [aleph] urls.plaintext = "/plaintext" @@ -61,7 +61,7 @@ os = "Linux" orm = "Raw" platform = "Netty" webserver = "None" -versus = "None" +versus = "duct" [immutant] urls.plaintext = "/plaintext" diff --git a/frameworks/Clojure/http-kit/benchmark_config.json b/frameworks/Clojure/http-kit/benchmark_config.json index f29afef42f2..49783a766e4 100644 --- a/frameworks/Clojure/http-kit/benchmark_config.json +++ b/frameworks/Clojure/http-kit/benchmark_config.json @@ -22,28 +22,7 @@ "database_os": "Linux", "display_name": "http-kit", "notes": "", - "versus": "http-kit" - }, - "raw": { - "db_url": "/raw/db", - "query_url": "/raw/queries/", - "update_url": "/raw/updates/", - "fortune_url": "/raw/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "framework": "None", - "language": "Clojure", - "flavor": "None", - "orm": "Raw", - "platform": "Ring", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "http-kit", - "notes": "", - "versus": "http-kit" + "versus": "" } }] } diff --git a/frameworks/Clojure/http-kit/config.toml b/frameworks/Clojure/http-kit/config.toml index 8b3ea9f9133..4bb24ea6505 100644 --- a/frameworks/Clojure/http-kit/config.toml +++ b/frameworks/Clojure/http-kit/config.toml @@ -16,19 +16,4 @@ os = "Linux" orm = "Micro" platform = "Ring" webserver = "None" -versus = "http-kit" - -[raw] -urls.db = "/raw/db" -urls.query = "/raw/queries/" -urls.update = "/raw/updates/" -urls.fortune = "/raw/fortunes" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Ring" -webserver = "None" -versus = "http-kit" +versus = "" diff --git a/frameworks/Clojure/http-kit/http-kit-raw.dockerfile b/frameworks/Clojure/http-kit/http-kit-raw.dockerfile deleted file mode 100644 index f0f00881f3f..00000000000 --- a/frameworks/Clojure/http-kit/http-kit-raw.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM clojure:lein-2.8.1 -WORKDIR /http-kit -COPY src src -COPY project.clj project.clj -RUN lein deps -RUN lein uberjar - -EXPOSE 8080 - -CMD ["java", "-server", "-Dclojure.compiler.direct-linking=true", "-jar", "target/http-kit-standalone.jar"] diff --git a/frameworks/Clojure/http-kit/http-kit.dockerfile b/frameworks/Clojure/http-kit/http-kit.dockerfile index f0f00881f3f..3090b7b3781 100644 --- a/frameworks/Clojure/http-kit/http-kit.dockerfile +++ b/frameworks/Clojure/http-kit/http-kit.dockerfile @@ -1,10 +1,14 @@ -FROM clojure:lein-2.8.1 +FROM clojure:lein as lein WORKDIR /http-kit -COPY src src COPY project.clj project.clj RUN lein deps +COPY src src RUN lein uberjar +FROM amazoncorretto:25 +WORKDIR /http-kit +COPY --from=lein /http-kit/target/http-kit-standalone.jar app.jar + EXPOSE 8080 -CMD ["java", "-server", "-Dclojure.compiler.direct-linking=true", "-jar", "target/http-kit-standalone.jar"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] \ No newline at end of file diff --git a/frameworks/Clojure/http-kit/project.clj b/frameworks/Clojure/http-kit/project.clj index f7c4e3209d4..4d9a37b4f19 100644 --- a/frameworks/Clojure/http-kit/project.clj +++ b/frameworks/Clojure/http-kit/project.clj @@ -1,22 +1,17 @@ (defproject hello "http-kit" :description "FrameworkBenchmarks test implementations" :url "http://localhost:8080/" - :dependencies [[org.clojure/clojure "1.8.0"] - [compojure "1.4.0"] - [ring/ring-json "0.4.0"] + :dependencies [[org.clojure/clojure "1.12.4"] + [compojure "1.7.2"] + [ring/ring-json "0.5.1"] [org.clojure/tools.cli "0.2.1"] - [http-kit "2.1.19"] + [http-kit "2.8.1"] [javax.xml.bind/jaxb-api "2.2.12"] - [korma "0.4.2"] [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]] - ; [ch.qos.logback/logback-classic "1.1.2" :exclusions [org.slf4j/slf4j-api]] - ; [org.slf4j/jul-to-slf4j "1.7.7"] - ; [org.slf4j/jcl-over-slf4j "1.7.7"] - ; [org.slf4j/log4j-over-slf4j "1.7.7"] [ring/ring-jetty-adapter "1.4.0"] - [mysql/mysql-connector-java "5.1.47"] - [org.clojure/java.jdbc "0.3.7"] - [hikari-cp "1.5.0"] + [com.mysql/mysql-connector-j "9.6.0"] + [com.github.seancorfield/next.jdbc "1.3.1093"] + [hikari-cp "4.0.0"] [hiccup "1.0.5"]] :plugins [[lein-ring "0.9.7"]] :ring {:handler hello.handler/app} diff --git a/frameworks/Clojure/http-kit/src/hello/handler.clj b/frameworks/Clojure/http-kit/src/hello/handler.clj index 1dad047d788..1c0885e26c6 100644 --- a/frameworks/Clojure/http-kit/src/hello/handler.clj +++ b/frameworks/Clojure/http-kit/src/hello/handler.clj @@ -1,168 +1,106 @@ (ns hello.handler (:gen-class) - (:use compojure.core - ring.middleware.json - org.httpkit.server - [clojure.tools.cli :only [cli]] - korma.db - korma.core - hiccup.core - hiccup.util - hiccup.page) - (:require [compojure.handler :as handler] + (:require [next.jdbc :as jdbc] + [clojure.tools.cli :only [cli]] + [next.jdbc.result-set :as rs] + [compojure.core :refer [GET defroutes]] [compojure.route :as route] - [ring.util.response :as ring-resp] - [clojure.java.jdbc :as jdbc] - [hikari-cp.core :refer :all])) + [org.httpkit.server :refer [run-server]] + [hiccup.page :refer [html5]] + [hiccup.util :refer [escape-html]] + [hikari-cp.core :refer :all] + [ring.middleware.json :as json-middleware] + [ring.util.response :as ring-resp])) (defn sanitize-queries-param "Sanitizes the `queries` parameter. Clamps the value between 1 and 500. Invalid (string) values become 1." [queries] (let [n (try (Integer/parseInt queries) - (catch Exception e 1))] ; default to 1 on parse failure + (catch Exception _ 1))] (cond (< n 1) 1 (> n 500) 500 :else n))) -;; MySQL database connection -(defdb db-mysql - (mysql { - :classname "com.mysql.jdbc.Driver" - :subprotocol "mysql" - :subname "//tfb-database:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true&useSSL=false" - :user "benchmarkdbuser" - :password "benchmarkdbpass" - ;;OPTIONAL KEYS - :delimiters "" ;; remove delimiters - :maximum-pool-size 256})) - -;; Create HikariCP-pooled "raw" jdbc data source (defn make-hikari-data-source [] - (make-datasource {:auto-commit true - :read-only false - :connection-timeout 30000 - :validation-timeout 5000 - :idle-timeout 600000 - :max-lifetime 1800000 - :minimum-idle 10 - :maximum-pool-size 256 - :pool-name "db-pool" - :adapter "mysql" - :username "benchmarkdbuser" - :password "benchmarkdbpass" - :database-name "hello_world" - :server-name "tfb-database" - :port-number 3306 - :register-mbeans false})) + (make-datasource { + :idle-timeout 15000 + :max-lifetime 60000 + :minimum-idle 0 + :maximum-pool-size 1024 + :pool-name "db-pool" + :driver-class-name "com.mysql.cj.jdbc.Driver" + :jdbc-url "jdbc:mysql://tfb-database:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts=true&cacheRSMetadata=true&useSSL=false" + :username "benchmarkdbuser" + :password "benchmarkdbpass" + :register-mbeans false})) -;; Reuse a single HikariCP-pooled data source (def memoize-hikari-data-source (memoize make-hikari-data-source)) -;; Get a HikariCP-pooled "raw" jdbc connection -(defn db-mysql-raw [] {:datasource (memoize-hikari-data-source)}) +(defn db-mysql [] (memoize-hikari-data-source)) -;; Set up entity World and the database representation -(defentity world - (pk :id) - (table :world) - (entity-fields :id :randomNumber) ; Default fields for select - (database db-mysql)) -(defn get-random-world-korma - "Query a random World record from the database" - [] - (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000 - (select world - (where {:id id })))) - -(defn run-queries - "Run query repeatedly, return an array" - [queries] - (flatten ; Make it a list of maps - (take queries ; Number of queries to run - (repeatedly get-random-world-korma)))) - -(defn get-random-world-raw +(defn get-random-world "Query a random World record from the database" [] (let [id (inc (rand-int 9999))] - (jdbc/query (db-mysql-raw) [(str "select * from world where id = ?") id]))) + (jdbc/execute! (db-mysql) + ["select * from world where id = ?" id] + {:builder-fn rs/as-unqualified-lower-maps}))) -(defn run-queries-raw +(defn run-queries "Run query repeatedly, return an array" [queries] - (flatten ; Make it a list of maps + (flatten (take queries - (repeatedly get-random-world-raw)))) + (repeatedly get-random-world)))) -;; Set up entity Fortune and the database representation -(defentity fortune - (pk :id) - (table :fortune) - (entity-fields :id :message) - (database db-mysql)) - -(defn get-all-fortunes-korma - "Query all Fortune records from the database using Korma." - [] - (select fortune - (fields :id :message))) -(defn get-all-fortunes-raw - "Query all Fortune records from the database using JDBC." +(defn get-all-fortunes + "Query all Fortune records from the database using next.jdbc." [] - (jdbc/query (db-mysql-raw) [(str "select * from fortune")])) + (jdbc/execute! (db-mysql) + ["select * from fortune"] + {:builder-fn rs/as-unqualified-lower-maps})) (defn get-fortunes "Fetch the full list of Fortunes from the database, sort them by the fortune message text, and then return the results." [query-function] (sort-by #(:message %) - (conj - (query-function) - { :id 0 :message "Additional fortune added at request time." }))) + (conj + (query-function) + {:id 0 :message "Additional fortune added at request time."}))) (defn fortunes-hiccup "Render the given fortunes to simple HTML using Hiccup." [fortunes] (html5 - [:head - [:title "Fortunes"]] - [:body - [:table - [:tr - [:th "id"] - [:th "message"]] - (for [x fortunes] - [:tr - [:td (:id x)] - [:td (escape-html (:message x))]]) - ]])) - -(defn update-and-persist-korma - "Using Korma: Changes the :randomNumber of a number of world entities. + [:head + [:title "Fortunes"]] + [:body + [:table + [:tr + [:th "id"] + [:th "message"]] + (for [x fortunes] + [:tr + [:td (:id x)] + [:td (escape-html (:message x))]]) + ]])) + + +(defn update-and-persist + "Using next.jdbc: Changes the :randomNumber of a number of world entities. Persists the changes to sql then returns the updated entities" [queries] - (let [results (map #(assoc % :randomNumber (inc (rand-int 9999))) (run-queries queries))] - (doseq [{:keys [id randomNumber]} results] - (update world - (set-fields {:randomNumber randomNumber}) - (where {:id id}))) - results)) - -(defn update-and-persist-raw - "Using JDBC: Changes the :randomNumber of a number of world entities. - Persists the changes to sql then returns the updated entities" - [queries] - (let [world (map #(assoc % :randomnumber (inc (rand-int 9999))) (run-queries-raw queries))] + (let [world (map #(assoc % :randomnumber (inc (rand-int 9999))) (run-queries queries))] (doseq [{:keys [id randomnumber]} world] - (jdbc/update! - (db-mysql-raw) - :world {:randomnumber randomnumber} - ["id = ?" id])) + (jdbc/execute-one! + (db-mysql) + ["UPDATE world SET randomnumber = ? WHERE id = ?" randomnumber id])) world)) (defn json-serialization @@ -173,47 +111,24 @@ (defn single-query-test "Test 2: Single database query" [] - (ring-resp/response (first (run-queries 1)))) - -(defn multiple-queries-test - "Test 3: Multiple database queries" - [queries] - (-> queries - (sanitize-queries-param) - (run-queries) - (ring-resp/response))) - -(defn single-query-test-raw - "Test 2: Single database query (raw)" - [] (-> 1 - (run-queries-raw) + (run-queries) (first) (ring-resp/response))) -(defn multiple-queries-test-raw - "Test 3: Multiple database queries (raw)" +(defn multiple-queries-test + "Test 3: Multiple database queries" [queries] (-> queries (sanitize-queries-param) - (run-queries-raw) + (run-queries) (ring-resp/response))) (defn fortune-test "Test 4: Fortunes" [] (-> - (get-fortunes get-all-fortunes-korma) - (fortunes-hiccup) - (ring-resp/response) - (ring-resp/content-type "text/html") - (ring-resp/charset "utf-8"))) - -(defn fortune-test-raw - "Test 4: Fortunes Raw" - [] - (-> - (get-fortunes get-all-fortunes-raw) + (get-fortunes get-all-fortunes) (fortunes-hiccup) (ring-resp/response) (ring-resp/content-type "text/html") @@ -224,15 +139,7 @@ [queries] (-> queries (sanitize-queries-param) - (update-and-persist-korma) - (ring-resp/response))) - -(defn db-updates-raw - "Test 5: Database updates Raw" - [queries] - (-> queries - (sanitize-queries-param) - (update-and-persist-raw) + (update-and-persist) (ring-resp/response))) (def plaintext @@ -243,47 +150,29 @@ ;; Define route handlers (defroutes app-routes - (GET "/" [] "Hello, World!") - (GET "/plaintext" [] plaintext) - (GET "/json" [] (json-serialization)) - (GET "/db" [] (single-query-test)) - (GET "/queries/:queries" [queries] (multiple-queries-test queries)) - (GET "/queries/" [] (multiple-queries-test 1)) ; When param is omitted - (GET "/fortunes" [] (fortune-test)) - (GET "/updates/:queries" [queries] (db-updates queries)) - (GET "/updates/" [] (db-updates 1)) ; When param is omitted - (GET "/raw/db" [] (single-query-test-raw)) - (GET "/raw/queries/:queries" [queries] (multiple-queries-test-raw queries)) - (GET "/raw/queries/" [] (multiple-queries-test-raw 1)) ; When param is omitted - (GET "/raw/fortunes" [] (fortune-test-raw)) - (GET "/raw/updates/:queries" [queries] (db-updates-raw queries)) - (GET "/raw/updates/" [] (db-updates-raw 1)) ; When param is omitted - (route/not-found "Not Found")) - -(defn parse-port [s] - "Convert stringy port number int. Defaults to 8080." - (cond - (string? s) (Integer/parseInt s) - (instance? Integer s) s - (instance? Long s) (.intValue ^Long s) - :else 8080)) + (GET "/" [] "Hello, World!") + (GET "/plaintext" [] plaintext) + (GET "/json" [] (json-serialization)) + (GET "/db" [] (single-query-test)) + (GET "/queries/:queries" [queries] (multiple-queries-test queries)) + (GET "/queries/" [] (multiple-queries-test 1)) + (GET "/fortunes" [] (fortune-test)) + (GET "/updates/:queries" [queries] (db-updates queries)) + (GET "/updates/" [] (db-updates 1)) + (route/not-found "Not Found")) + +(def app + "Format responses as JSON" + (-> app-routes + (json-middleware/wrap-json-response))) (defn start-server [{:keys [port]}] - ;; Format responses as JSON - (let [handler (wrap-json-response app-routes) + (let [handler (json-middleware/wrap-json-response app-routes) cpu (.availableProcessors (Runtime/getRuntime))] - ;; double worker threads should increase database access performance (run-server handler {:port port :thread (* 2 cpu)}) (println (str "http-kit server listens at :" port)))) (defn -main [& args] - (let [[options _ banner] - (cli args - ["-p" "--port" "Port to listen" :default 8080 :parse-fn parse-port] - ["--[no-]help" "Print this help"])] - (when (:help options) - (println banner) - (System/exit 0)) - (start-server options))) + (start-server {:port 8080})) diff --git a/frameworks/Clojure/kit/deps.edn b/frameworks/Clojure/kit/deps.edn index 9fc78535261..a7cf020253b 100644 --- a/frameworks/Clojure/kit/deps.edn +++ b/frameworks/Clojure/kit/deps.edn @@ -14,13 +14,13 @@ metosin/muuntaja {:mvn/version "0.6.11"} ;; HTML templating - selmer/selmer {:mvn/version "1.12.62"} - org.clojars.jj/majavat {:mvn/version "1.13.0"} + selmer/selmer {:mvn/version "1.12.70"} + org.clojars.jj/majavat {:mvn/version "1.19.0"} hiccup/hiccup {:mvn/version "2.0.0"} ;; Database org.postgresql/postgresql {:mvn/version "42.7.8"} - org.clojars.jj/boa-sql {:mvn/version "1.0.0"} + org.clojars.jj/boa-sql {:mvn/version "1.0.1"} ;; kit Libs diff --git a/frameworks/Clojure/kit/resources/html/majavat-fortunes.html b/frameworks/Clojure/kit/resources/html/majavat-fortunes.html new file mode 100644 index 00000000000..18f8d52cb00 --- /dev/null +++ b/frameworks/Clojure/kit/resources/html/majavat-fortunes.html @@ -0,0 +1,15 @@ + + +Fortunes + + + + {% each message in messages %} + + + + + {% endeach %} +
idmessage
{{message.id}}{{message.message}}
+ + \ No newline at end of file diff --git a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/core.clj b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/core.clj index fe893e40441..58deed80023 100644 --- a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/core.clj +++ b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/core.clj @@ -4,8 +4,6 @@ [integrant.core :as ig] [io.github.kit-clj.te-bench.config :as config] [io.github.kit-clj.te-bench.env :refer [defaults]] - - ;; Edges [io.github.kit-clj.te-bench.cache.inmem] [io.github.kit-clj.te-bench.db.sql.hikari] [io.github.kit-clj.te-bench.web.handler] diff --git a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj index c02f3621c49..f8bcc1786f6 100644 --- a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj +++ b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/controllers/bench.clj @@ -1,14 +1,13 @@ (ns io.github.kit-clj.te-bench.web.controllers.bench (:require [clojure.core.cache :as cache] - [next.jdbc :as jdbc] - [next.jdbc.result-set :as rs] - [jj.majavat :as majavat] - [jj.sql.boa :as boa] [hiccup.page :as hp] [hiccup.util :as hu] + [jj.majavat :as majavat] [jj.majavat.renderer :refer [->StringRenderer]] - [jj.majavat.renderer.sanitizer :refer [->Html]] + [jj.sql.boa :as boa] + [next.jdbc :as jdbc] + [next.jdbc.result-set :as rs] [ring.util.http-response :as http-response] [selmer.parser :as parser])) @@ -19,9 +18,8 @@ (def ^:const HELLO_WORLD "Hello, World!") (def ^:const MAX_ID_ZERO_IDX 9999) (def ^:const CACHE_TTL (* 24 60 60)) -(def ^:private render-fortune (majavat/build-renderer "html/fortunes.html" - {:renderer (->StringRenderer - {:sanitizer (->Html)})})) +(def ^:private render-fortune (majavat/build-html-renderer "html/majavat-fortunes.html" + {:renderer (->StringRenderer)})) (defn render-hiccup-fortune [fortunes] (hp/html5 @@ -37,7 +35,7 @@ [:td (:id x)] [:td (hu/escape-html (:message x))]])]])) -(def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "sql/fortunes.sql")) +(def query-fortunes (boa/build-query (boa/->NextJdbcAdapter) "sql/fortunes.sql")) (def selmer-opts {:custom-resource-path (clojure.java.io/resource "html")}) (defn selmer-html-response diff --git a/frameworks/Clojure/ring-http-exchange/benchmark_config.json b/frameworks/Clojure/ring-http-exchange/benchmark_config.json index b0381b921ac..b4103ce3dbc 100755 --- a/frameworks/Clojure/ring-http-exchange/benchmark_config.json +++ b/frameworks/Clojure/ring-http-exchange/benchmark_config.json @@ -14,7 +14,7 @@ "language": "Clojure", "flavor": "None", "orm": "Raw", - "platform": "None", + "platform": "Ring", "webserver": "None", "os": "Linux", "database_os": "Linux", @@ -34,7 +34,7 @@ "language": "Clojure", "flavor": "None", "orm": "Raw", - "platform": "None", + "platform": "Ring", "webserver": "None", "os": "Linux", "database_os": "Linux", @@ -42,9 +42,7 @@ "notes": "", "versus": "httpserver-robaho" }, - "graalvm": { - "json_url": "/json", - "plaintext_url": "/plaintext", + "robaho-is": { "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", @@ -54,17 +52,15 @@ "language": "Clojure", "flavor": "None", "orm": "Raw", - "platform": "None", + "platform": "Ring", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ring-http-exchange-graalvm", + "display_name": "ring-http-exchange-robaho-is", "notes": "", - "versus": "ring-http-exchange" + "versus": "ring-http-exchange-robaho" }, - "robaho-graalvm": { - "json_url": "/json", - "plaintext_url": "/plaintext", + "robaho-async": { "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", @@ -74,14 +70,32 @@ "language": "Clojure", "flavor": "None", "orm": "Raw", - "platform": "None", + "platform": "Ring", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ring-http-exchange-robaho-graalvm", + "display_name": "ring-http-exchange-robaho-async", "notes": "", "versus": "ring-http-exchange-robaho" }, + "robaho-vertx": { + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "Ring", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange-robaho-vertx", + "notes": "", + "versus": "ring-http-exchange-robaho-async" + }, "robaho-semeru": { "json_url": "/json", "plaintext_url": "/plaintext", @@ -94,7 +108,7 @@ "language": "Clojure", "flavor": "None", "orm": "Raw", - "platform": "None", + "platform": "Ring", "webserver": "None", "os": "Linux", "database_os": "Linux", diff --git a/frameworks/Clojure/ring-http-exchange/config.toml b/frameworks/Clojure/ring-http-exchange/config.toml index 17193d6169a..2c931f45bc9 100644 --- a/frameworks/Clojure/ring-http-exchange/config.toml +++ b/frameworks/Clojure/ring-http-exchange/config.toml @@ -15,8 +15,7 @@ platform = "httpserver" webserver = "None" versus = "httpserver" - -[graalvm] +[robaho] urls.plaintext = "/plaintext" urls.json = "/json" urls.fortune = "/fortunes" @@ -28,11 +27,9 @@ os = "Linux" orm = "Raw" platform = "httpserver" webserver = "None" -versus = "httpserver-graalvm" +versus = "httpserver-robaho" -[robaho] -urls.plaintext = "/plaintext" -urls.json = "/json" +[robaho-is] urls.fortune = "/fortunes" approach = "Realistic" classification = "Platform" @@ -42,11 +39,21 @@ os = "Linux" orm = "Raw" platform = "httpserver" webserver = "None" -versus = "httpserver-robaho" +versus = "ring-http-exchange-robaho" -[robaho-graalvm] -urls.plaintext = "/plaintext" -urls.json = "/json" +[robaho-async] +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "ring-http-exchange-robaho" + +[robaho-vertx] urls.fortune = "/fortunes" approach = "Realistic" classification = "Platform" @@ -56,4 +63,4 @@ os = "Linux" orm = "Raw" platform = "httpserver" webserver = "None" -versus = "httpserver-robaho-graalvm" +versus = "ring-http-exchange-robaho-async" \ No newline at end of file diff --git a/frameworks/Clojure/ring-http-exchange/project.clj b/frameworks/Clojure/ring-http-exchange/project.clj index e0734cff1a5..d5c5de0e5f2 100644 --- a/frameworks/Clojure/ring-http-exchange/project.clj +++ b/frameworks/Clojure/ring-http-exchange/project.clj @@ -4,13 +4,16 @@ :license {:name "EPL-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} - :dependencies [[org.clojure/clojure "1.12.3"] + :dependencies [[org.clojure/clojure "1.12.4"] [org.clojure/tools.logging "1.3.0"] - [org.clojars.jj/ring-http-exchange "1.2.9"] + [org.clojars.jj/ring-http-exchange "1.4.1"] [seancorfield/next.jdbc "1.2.659"] - [org.clojars.jj/majavat "1.13.0"] + [org.clojars.jj/majavat "1.20.1"] + [org.clojars.jj/boa-sql "1.0.8"] + [org.clojars.jj/async-boa-sql "1.0.8"] [hikari-cp "3.3.0"] - [org.clojars.jj/boa-sql "1.0.0"] + [org.clojars.jj/arminio "1.0.0"] + [org.clojars.jj/vertx-pg-client-async-boa-adapter "1.0.1"] [org.postgresql/postgresql "42.7.8"] [metosin/jsonista "0.3.13"] ] diff --git a/frameworks/Clojure/ring-http-exchange/resources/fortune.html b/frameworks/Clojure/ring-http-exchange/resources/fortune.html index 3f4dd2fca9e..25d4ed12559 100644 --- a/frameworks/Clojure/ring-http-exchange/resources/fortune.html +++ b/frameworks/Clojure/ring-http-exchange/resources/fortune.html @@ -4,12 +4,12 @@ - {% for message in messages %} + {% each message in messages %} - {% endfor %} + {% endeach %}
idmessage
{{message.id}} {{message.message}}
\ No newline at end of file diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile deleted file mode 100644 index ad82982bcd9..00000000000 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM clojure:lein as lein -WORKDIR /ring-http-exchange -COPY project.clj project.clj -COPY resources resources -COPY src src -RUN lein uberjar - -FROM ghcr.io/graalvm/graalvm-community:25 -WORKDIR /ring-http-exchange -COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-async.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-async.dockerfile new file mode 100644 index 00000000000..db99f8db86d --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-async.dockerfile @@ -0,0 +1,14 @@ +FROM clojure:lein as lein +WORKDIR /ring-http-exchange +COPY project.clj project.clj +COPY resources resources +COPY src src +RUN lein with-profile robaho uberjar + +FROM amazoncorretto:25 +WORKDIR /ring-http-exchange +COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar", "--async"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile deleted file mode 100644 index 151a6746e12..00000000000 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM clojure:lein as lein -WORKDIR /ring-http-exchange -COPY project.clj project.clj -COPY resources resources -COPY src src -RUN lein with-profile robaho uberjar - -FROM ghcr.io/graalvm/graalvm-community:25 -WORKDIR /ring-http-exchange -COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-is.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-is.dockerfile new file mode 100644 index 00000000000..bda7445dbdc --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-is.dockerfile @@ -0,0 +1,14 @@ +FROM clojure:lein as lein +WORKDIR /ring-http-exchange +COPY project.clj project.clj +COPY resources resources +COPY src src +RUN lein with-profile robaho uberjar + +FROM amazoncorretto:25 +WORKDIR /ring-http-exchange +COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar", "--inputstream", "--async"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile index bffbb459912..c0577fd69eb 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-Xtune:throughput", "-Xgcpolicy:optthruput", "-XX:MaxRAMPercentage=70", "-XX:+UseContainerSupport", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] +CMD ["java", "-Xtune:throughput", "-Xgcpolicy:optthruput", "-XX:MaxRAMPercentage=70", "-XX:+UseContainerSupport", "-Dclojure.compiler.direct-linking=true", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-vertx.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-vertx.dockerfile new file mode 100644 index 00000000000..134ea9079bb --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-vertx.dockerfile @@ -0,0 +1,14 @@ +FROM clojure:lein as lein +WORKDIR /ring-http-exchange +COPY project.clj project.clj +COPY resources resources +COPY src src +RUN lein with-profile robaho uberjar + +FROM amazoncorretto:25 +WORKDIR /ring-http-exchange +COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar", "--vertx", "--async"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile index 095040b74d0..80606b6e48e 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile index f7b8946ab06..e9cecefc41d 100644 --- a/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.dockerfile @@ -11,4 +11,4 @@ COPY --from=lein /ring-http-exchange/target/ring-http-server-1.0.0-standalone.ja EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-Dsun.net.httpserver.nodelay=true", "-XX:MaxRAMPercentage=70", "-Dclojure.compiler.direct-linking=true", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj index 6629b7c6a39..928b86184bb 100644 --- a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj @@ -1,65 +1,73 @@ (ns ring-http-exchange.benchmark (:gen-class) (:require - [jj.majavat :as majavat] - [jj.majavat.renderer :refer [->StringRenderer]] - [jj.majavat.renderer.sanitizer :refer [->Html]] - [jj.sql.boa :as boa] - [jsonista.core :as json] [next.jdbc.connection :as connection] - [ring-http-exchange.core :as server]) + [ring-http-exchange.input-stream-handler :as input-stream-handler] + [ring-http-exchange.core :as server] + [ring-http-exchange.string-handler :as string-handler]) (:import (com.zaxxer.hikari HikariDataSource) - (java.util.concurrent Executors))) + (io.vertx.pgclient PgBuilder PgConnectOptions SslMode) + (io.vertx.sqlclient PoolOptions) + (java.util.concurrent Executors) + (jj.arminio.concurrent ProxyExecutorService))) -(defrecord Response [body status headers]) +(def db-spec + {:idle-timeout 150000 + :max-lifetime 300000 + :minimum-idle 10 + :maximum-pool-size 1024 + :dbtype "postgresql" + :host "tfb-database" + :dbname "hello_world" + :username "benchmarkdbuser" + :password "benchmarkdbpass"}) -(def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "fortune.sql")) +(def cached-thread-executor (Executors/newCachedThreadPool)) -(def db-spec {:auto-commit false - :connection-timeout 1000 - :validation-timeout 1000 - :idle-timeout 15000 - :max-lifetime 60000 - :minimum-idle 0 - :maximum-pool-size 128 - :register-mbeans false - :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass&prepareThreshold=1"} - ) -(def ^:private ^:const hello-world "Hello, World!") -(def ^:private ^:const additional-message {:id 0 - :message "Additional fortune added at request time."}) -(def ^:private ^:const fortune-headers {"Server" "ring-http-exchange" - "Content-Type" "text/html; charset=UTF-8"}) -(def ^:private ^:const json-headers {"Server" "ring-http-exchange" - "Content-Type" "application/json"}) -(def ^:private ^:const plain-text-headers {"Server" "ring-http-exchange" - "Content-Type" "text/plain"}) - -(def ^:private render-fortune (majavat/build-renderer "fortune.html" - {:renderer (->StringRenderer - {:sanitizer (->Html)})})) - -(defn- get-body [datasource] - (let [context (as-> (query-fortunes datasource) fortunes - (conj fortunes additional-message) - (sort-by :message fortunes))] - (render-fortune {:messages context}))) +(defn create-vertx-pool [] + (let [connect-opts (-> (PgConnectOptions.) + (.setHost "tfb-database") + (.setPort 5432) + (.setDatabase "hello_world") + (.setUser "benchmarkdbuser") + (.setPassword "benchmarkdbpass") + (.setSslMode SslMode/DISABLE) + (.setCachePreparedStatements true) + (.setPreparedStatementCacheMaxSize 256)) + pool-opts (-> (PoolOptions.) + (.setMaxSize 512))] + (-> (PgBuilder/pool) + (.connectingTo connect-opts) + (.with pool-opts) + (.build)))) (defn -main - [& _] + [& args] (println "Starting server on port 8080") - (let [datasource (connection/->pool HikariDataSource db-spec)] - (server/run-http-server - (fn [req] - (case (req :uri) - "/plaintext" (Response. hello-world 200 plain-text-headers) - "/json" (Response. (json/write-value-as-string {:message hello-world}) 200 json-headers) - "/fortunes" (let [body (get-body datasource)] (Response. body 200 fortune-headers)) - (Response. hello-world 200 {"Server" "ring-http-exchange" - "Content-Type" "text/plain"}))) - {:port 8080 - :host "0.0.0.0" - :record-support? true - :executor (Executors/newVirtualThreadPerTaskExecutor)}))) \ No newline at end of file + (let [default-executor-service (ProxyExecutorService. cached-thread-executor) + default-server-config {:port 8080 + :host "0.0.0.0" + :lazy-request-map? true + :executor default-executor-service} + + datasource (connection/->pool HikariDataSource db-spec) + use-inputstream? (some #{"--inputstream"} args) + async? (some #{"--async"} args) + vertx? (some #{"--vertx"} args) + ] + (.addDataSourceProperty datasource "tcpKeepAlive" "true") + (.addDataSourceProperty datasource "useSSL" false) + (.addDataSourceProperty datasource "prepStmtCacheSize" "250") + (.addDataSourceProperty datasource "cachePrepStmts" "true") + (.addDataSourceProperty datasource "prepStmtCacheSqlLimit" "2048") + + (let [handler (cond + vertx? (string-handler/get-vertx-handler (create-vertx-pool)) + async? (string-handler/get-async-handler datasource cached-thread-executor) + use-inputstream? (input-stream-handler/get-handler datasource) + :else (string-handler/get-handler datasource)) + config (cond-> default-server-config + async? (assoc :async? true))] + (server/run-http-server handler config)))) diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/input_stream_handler.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/input_stream_handler.clj new file mode 100644 index 00000000000..b5a2c8bf337 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/input_stream_handler.clj @@ -0,0 +1,31 @@ +(ns ring-http-exchange.input-stream-handler + (:require + [jj.majavat :as majavat] + [jj.majavat.renderer :refer [->InputStreamRenderer]] + [ring-http-exchange.model :as model])) + +(defrecord Response [body status headers]) + +(def ^:private ^:const fortune-headers {"Server" "ring-http-exchange" + "Content-Type" "text/html; charset=UTF-8"}) + +(def ^:private render-fortune (majavat/build-html-renderer "fortune.html" + {:renderer (->InputStreamRenderer)})) + +(defn create-callback [respond] + (fn [fortune-data] + (respond + (Response. + (render-fortune {:messages + (sort-by :message + (conj fortune-data {:id 0 + :message "Additional fortune added at request time."}))}) + 200 + fortune-headers)))) + +(defn get-handler [data-source] + (fn [req respond raise] + (if (.equals "/fortunes" (req :uri)) + (model/vertx-query-fortunes data-source (create-callback respond) raise) + (Response. model/hello-world 200 {})))) + diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/model.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/model.clj new file mode 100644 index 00000000000..cf0445a3c71 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/model.clj @@ -0,0 +1,24 @@ +(ns ring-http-exchange.model + (:require [jj.sql.boa :as sync-boa] + [jj.sql.async-boa :as async-boa] + [jj.sql.boa.query.next-jdbc :as next-jdbc-adapter] + [jj.sql.boa.query.vertx-pg :as vertx-adapter] + [jj.sql.boa.query.next-jdbc-async :as async-next-jdbc-adapter] + [jsonista.core :as json]) + (:import (java.util.concurrent Executors))) + +(def executor (Executors/newVirtualThreadPerTaskExecutor)) + +(def ^:const hello-world "Hello, World!") +(def query-fortunes (sync-boa/build-query (next-jdbc-adapter/->NextJdbcAdapter) "fortune.sql")) +(def async-query-fortunes (async-boa/build-async-query (async-next-jdbc-adapter/->NextJdbcAdapter executor) "fortune.sql")) +(def vertx-query-fortunes (async-boa/build-async-query (vertx-adapter/->VertxPgAdapter) "fortune.sql")) + +(defn json-body [] + (json/write-value-as-string {:message hello-world})) + +(defn fortunes-body [data-source] + {:messages (as-> (query-fortunes data-source) fortunes + (conj fortunes {:id 0 + :message "Additional fortune added at request time."}) + (sort-by :message fortunes))}) diff --git a/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/string_handler.clj b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/string_handler.clj new file mode 100644 index 00000000000..1944c4db7c3 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/string_handler.clj @@ -0,0 +1,59 @@ +(ns ring-http-exchange.string-handler + (:require + [jj.majavat :as majavat] + [ring-http-exchange.model :as model])) + +(defrecord Response [body status headers]) +(def ^:private ^:const fortune-headers {"Server" "ring-http-exchange" + "Content-Type" "text/html; charset=UTF-8"}) +(def ^:private ^:const json-headers {"Server" "ring-http-exchange" + "Content-Type" "application/json"}) +(def ^:private ^:const plain-text-headers {"Server" "ring-http-exchange" + "Content-Type" "text/plain"}) + +(def ^:private render-fortune (majavat/build-html-renderer "fortune.html")) + +(defn create-callback + ([respond] + (fn [fortune-data] + (respond + (Response. + (render-fortune {:messages + (sort-by :message + (conj fortune-data {:id 0 + :message "Additional fortune added at request time."}))}) + 200 + fortune-headers)))) + ([respond ^java.util.concurrent.Executor executor] + (fn [fortune-data] + (.execute executor + (fn [] + (respond + (Response. + (render-fortune {:messages + (sort-by :message + (conj fortune-data {:id 0 + :message "Additional fortune added at request time."}))}) + 200 + fortune-headers))))))) + +(defn get-handler [data-source] + (fn [req] + (case (req :uri) + "/plaintext" (Response. model/hello-world 200 plain-text-headers) + "/json" (Response. (model/json-body) 200 json-headers) + "/fortunes" (Response. (render-fortune (model/fortunes-body data-source)) 200 fortune-headers) + (Response. model/hello-world 200 {"Server" "ring-http-exchange" + "Content-Type" "text/plain"})))) + +(defn get-async-handler [data-source executor] + (fn [req respond raise] + (if (.equals "/fortunes" (req :uri)) + (model/async-query-fortunes data-source (create-callback respond executor) raise) + (Response. model/hello-world 200 plain-text-headers)))) + +(defn get-vertx-handler [data-source] + (fn [req respond raise] + (if (.equals "/fortunes" (req :uri)) + (model/vertx-query-fortunes data-source (create-callback respond) raise) + (Response. model/hello-world 200 plain-text-headers)))) diff --git a/frameworks/Crystal/amber/benchmark_config.json b/frameworks/Crystal/amber/benchmark_config.json index 5fe0157d83a..f31719611d3 100644 --- a/frameworks/Crystal/amber/benchmark_config.json +++ b/frameworks/Crystal/amber/benchmark_config.json @@ -3,10 +3,6 @@ "tests": [{ "default": { "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", diff --git a/frameworks/Crystal/grip/README.md b/frameworks/Crystal/grip/README.md index 2a659d24e96..5d23a025795 100644 --- a/frameworks/Crystal/grip/README.md +++ b/frameworks/Crystal/grip/README.md @@ -8,13 +8,13 @@ Grip is a microframework for building RESTful web applications, with ease and jo ### Test Type Implementation Source Code -* [JSON](grip.cr) -* [PLAINTEXT](grip.cr) -* [DB](grip.cr) -* [QUERY](grip.cr) -* [CACHED QUERY](grip.cr) -* [UPDATE](grip.cr) -* [FORTUNES](grip.cr) +* [JSON](server-postgres.cr) +* [PLAINTEXT](server-postgres.cr) +* [DB](server-postgres.cr) +* [QUERY](server-postgres.cr) +* [CACHED QUERY](server-postgres.cr) +* [UPDATE](server-postgres.cr) +* [FORTUNES](server-postgres.cr) ## Important Libraries The tests were run with: diff --git a/frameworks/Crystal/grip/benchmark_config.json b/frameworks/Crystal/grip/benchmark_config.json index 56cd319dfc9..2f4257604ba 100644 --- a/frameworks/Crystal/grip/benchmark_config.json +++ b/frameworks/Crystal/grip/benchmark_config.json @@ -1,30 +1,46 @@ { "framework": "grip", - "tests": [ - { - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Grip", - "language": "Crystal", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Grip", - "notes": "", - "versus": "None" - } + "tests": [{ + "default": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "grip", + "language": "Crystal", + "flavor": "None", + "orm": "micro", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Grip (PostgreSQL)", + "notes": "", + "versus": "crystal" + }, + "concurrent-queries": { + "query_url": "/queries?concurrency=2&queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "grip", + "language": "Crystal", + "flavor": "None", + "orm": "micro", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Grip (PostgreSQL) - Concurrent Queries", + "notes": "", + "versus": "crystal" } - ] + }] } diff --git a/frameworks/Crystal/grip/config.toml b/frameworks/Crystal/grip/config.toml index 6371ae310fc..4cc5df333dc 100644 --- a/frameworks/Crystal/grip/config.toml +++ b/frameworks/Crystal/grip/config.toml @@ -10,10 +10,22 @@ urls.update = "/updates?queries=" urls.fortune = "/fortunes" approach = "Realistic" classification = "Micro" -database = "postgres" +database = "Postgres" database_os = "Linux" os = "Linux" -orm = "Raw" +orm = "micro" platform = "None" webserver = "None" -versus = "None" +versus = "crystal" + +[concurrent-queries] +urls.query = "/queries?concurrency=2&queries=" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "micro" +platform = "None" +webserver = "None" +versus = "crystal" diff --git a/frameworks/Crystal/grip/grip-concurrent-queries.dockerfile b/frameworks/Crystal/grip/grip-concurrent-queries.dockerfile new file mode 100644 index 00000000000..f8beba7e0f4 --- /dev/null +++ b/frameworks/Crystal/grip/grip-concurrent-queries.dockerfile @@ -0,0 +1,18 @@ +FROM crystallang/crystal:1.12.1 + +WORKDIR /grip +COPY views views +COPY run.sh run.sh +COPY server-postgres.cr server-postgres.cr +COPY shard.yml shard.yml + +ENV GC_MARKERS 1 +ENV ENVIRONMENT PRODUCTION +ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=128&max_idle_pool_size=128 + +RUN shards install +RUN crystal build --release --no-debug server-postgres.cr + +EXPOSE 8080 + +CMD bash run.sh diff --git a/frameworks/Crystal/grip/grip.dockerfile b/frameworks/Crystal/grip/grip.dockerfile index a5e1efb3305..8a960d01b9e 100644 --- a/frameworks/Crystal/grip/grip.dockerfile +++ b/frameworks/Crystal/grip/grip.dockerfile @@ -3,14 +3,15 @@ FROM crystallang/crystal:1.18.2 WORKDIR /grip COPY views views COPY run.sh run.sh -COPY grip.cr grip.cr +COPY server-postgres.cr server-postgres.cr COPY shard.yml shard.yml +ENV GC_MARKERS 1 +ENV ENVIRONMENT PRODUCTION ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56 -ENV GRIP_ENV production RUN shards install -RUN crystal build --release --no-debug grip.cr +RUN crystal build --release --no-debug server-postgres.cr EXPOSE 8080 diff --git a/frameworks/Crystal/grip/run.sh b/frameworks/Crystal/grip/run.sh index bcf63c4c9d0..116b619136f 100755 --- a/frameworks/Crystal/grip/run.sh +++ b/frameworks/Crystal/grip/run.sh @@ -1,7 +1,7 @@ #!/bin/bash for i in $(seq 1 $(nproc --all)); do - ./grip & + ./server-postgres & done wait diff --git a/frameworks/Crystal/grip/grip.cr b/frameworks/Crystal/grip/server-postgres.cr similarity index 100% rename from frameworks/Crystal/grip/grip.cr rename to frameworks/Crystal/grip/server-postgres.cr diff --git a/frameworks/Crystal/grip/shard.yml b/frameworks/Crystal/grip/shard.yml index 41ac7355622..420beab25cb 100644 --- a/frameworks/Crystal/grip/shard.yml +++ b/frameworks/Crystal/grip/shard.yml @@ -4,7 +4,7 @@ version: 0.2.0 dependencies: grip: github: grip-framework/grip - version: 4.0.0 + version: 4.1.0 pg: github: will/crystal-pg diff --git a/frameworks/D/collie/README.md b/frameworks/D/collie/README.md deleted file mode 100644 index e9cb3887c14..00000000000 --- a/frameworks/D/collie/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Collie Benchmarking Test - -This is the netty portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -### JSON Encoding Test -* [JSON test source](collie/source/get.d) - -## Requirements -* Dlang > 2.072 - -## Test URLs - -### JSON Encoding Test - - http://localhost:8080/json - -### PlanText Test - - http://localhost:8080/plaintext diff --git a/frameworks/D/collie/benchmark_config.json b/frameworks/D/collie/benchmark_config.json deleted file mode 100644 index 4496ad206e3..00000000000 --- a/frameworks/D/collie/benchmark_config.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "framework": "collie", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8085, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "Collie", - "language": "D", - "flavor": "DLang2", - "orm": "Raw", - "platform": "Collie", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Collie", - "notes": "", - "versus": "Collie" - }, - "ldc": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8085, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "Collie", - "language": "D", - "flavor": "DLang2", - "orm": "Raw", - "platform": "Collie", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Collie", - "notes": "", - "versus": "Collie" - } - }] -} diff --git a/frameworks/D/collie/collie-ldc.dockerfile b/frameworks/D/collie/collie-ldc.dockerfile deleted file mode 100644 index 421b77b876a..00000000000 --- a/frameworks/D/collie/collie-ldc.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM dlang2/ldc-ubuntu:1.15.0 - -ADD ./ /collie -WORKDIR /collie - -RUN dub upgrade --verbose -RUN dub build -f -b release --compiler=ldc2 - -EXPOSE 8085 - -CMD ["./http"] diff --git a/frameworks/D/collie/collie.dockerfile b/frameworks/D/collie/collie.dockerfile deleted file mode 100644 index 0a522756b3e..00000000000 --- a/frameworks/D/collie/collie.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM dlang2/dmd-ubuntu:2.085.1 - -ADD ./ /collie -WORKDIR /collie - -RUN dub upgrade --verbose -RUN dub build -f -b release - -EXPOSE 8085 - -CMD ["./http"] diff --git a/frameworks/D/collie/config.toml b/frameworks/D/collie/config.toml deleted file mode 100644 index 2ace65a9749..00000000000 --- a/frameworks/D/collie/config.toml +++ /dev/null @@ -1,28 +0,0 @@ -[framework] -name = "collie" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Collie" -webserver = "None" -versus = "Collie" - -[ldc] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Collie" -webserver = "None" -versus = "Collie" diff --git a/frameworks/D/collie/dub.json b/frameworks/D/collie/dub.json deleted file mode 100644 index 9e1e2c2a657..00000000000 --- a/frameworks/D/collie/dub.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "http", - "description": "A minimal D application.", - "copyright": "Copyright © 2016, dsby", - "authors": ["dsby"], - "targetType": "executable", - "dependencies": { - "collie" : "~>0.10.16" - } -} diff --git a/frameworks/D/collie/source/app.d b/frameworks/D/collie/source/app.d deleted file mode 100644 index dc8ef147351..00000000000 --- a/frameworks/D/collie/source/app.d +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Collie - An asynchronous event-driven network framework using Dlang development - * - * Copyright (C) 2015-2016 Shanghai Putao Technology Co., Ltd - * - * Developer: putao's Dlang team - * - * Licensed under the Apache-2.0 License. - * - */ -import std.stdio; -import std.experimental.logger; -import std.exception; -import std.typecons; -import std.functional; -import std.parallelism; - -import collie.net; -import collie.codec.http; -import collie.codec.http.server; - -debug { - extern(C) __gshared string[] rt_options = [ "gcopt=profile:1"];// maxPoolSize:50" ]; -} - - - -void main() -{ - RequestHandler newHandler(RequestHandler,HTTPMessage msg) - { - import get; - import post; - - if(msg.method == HTTPMethod.HTTP_GET) - return new GetHandler(); - if(msg.method == HTTPMethod.HTTP_POST) - return new PostHandler(); - return null; - } - - writeln("Edit source/app.d to start your project."); - globalLogLevel(LogLevel.warning); - HTTPServerOptions option = new HTTPServerOptions(); - option.handlerFactories ~= toDelegate(&newHandler); - option.threads = totalCPUs; - HttpServer server = new HttpServer(option); - - HTTPServerOptions.IPConfig ipconfig ; - ipconfig.address = new InternetAddress("0.0.0.0", 8085); - - HTTPServerOptions.IPConfig ipconfig2 ; - ipconfig2.address = new Internet6Address("0::0", 8085); - - server.addBind(ipconfig); - server.addBind(ipconfig2); - server.start(); -} diff --git a/frameworks/D/collie/source/get.d b/frameworks/D/collie/source/get.d deleted file mode 100644 index 602feb38c92..00000000000 --- a/frameworks/D/collie/source/get.d +++ /dev/null @@ -1,64 +0,0 @@ -module get; - -import collie.codec.http; -import collie.codec.http.server; -import std.json; -import std.typecons; -import std.exception; -import kiss.container.Vector; -import request; - -final class GetHandler : BaseHandler -{ - override void onEOM() nothrow - { - collectException({ - switch(_header.getPath) - { - case "/json": - json(); - break; - case "/plaintext": - plaintext(); - break; - default: - index(); - break; - } - }()); - } - - void index() - { - auto build = scoped!ResponseBuilder(_downstream); - build.status(200,HTTPMessage.statusText(200)); - build.setBody(cast(ubyte[])"Hello, World!"); - build.header(HTTPHeaderCode.CONTENT_TYPE,"text/plain"); - build.header(HTTPHeaderCode.DATE, printDate); - build.sendWithEOM(); - } - - void json() - { - JSONValue js; - js["message"] = "Hello, World!"; - - auto build = scoped!ResponseBuilder(_downstream); - build.status(200,HTTPMessage.statusText(200)); - build.setBody(cast(ubyte[])(js.toString)); - build.header(HTTPHeaderCode.CONTENT_TYPE,"application/json"); - build.header(HTTPHeaderCode.DATE, printDate); - build.sendWithEOM(); - } - - void plaintext() - { - auto build = scoped!ResponseBuilder(_downstream); - build.status(200,HTTPMessage.statusText(200)); - build.setBody(cast(ubyte[])"Hello, World!"); - build.header(HTTPHeaderCode.CONTENT_TYPE,"text/plain"); - build.header(HTTPHeaderCode.DATE, printDate); - build.sendWithEOM(); - } -} - diff --git a/frameworks/D/collie/source/post.d b/frameworks/D/collie/source/post.d deleted file mode 100644 index 9e8dc859b9e..00000000000 --- a/frameworks/D/collie/source/post.d +++ /dev/null @@ -1,65 +0,0 @@ -module post; - - -import collie.codec.http; -import collie.codec.http.server; -import request; -import std.json; -import std.typecons; -import std.exception; -import kiss.container.Vector; - -final class PostHandler : BaseHandler -{ - override void onEOM() nothrow - { - collectException({ - switch(_header.getPath) - { - case "/json": - json(); - break; - case "/plaintext": - plaintext(); - break; - default: - index(); - break; - } - }()); - } - - void index() - { - auto build = scoped!ResponseBuilder(_downstream); - build.status(200,HTTPMessage.statusText(200)); - build.setBody(cast(ubyte[])"Hello, World!"); - build.header(HTTPHeaderCode.CONTENT_TYPE,"text/plain"); - build.header(HTTPHeaderCode.DATE, printDate); - build.sendWithEOM(); - } - - void json() - { - JSONValue js; - js["message"] = "Hello, World!"; - - auto build = scoped!ResponseBuilder(_downstream); - build.status(200,HTTPMessage.statusText(200)); - build.setBody(cast(ubyte[])(js.toString)); - build.header(HTTPHeaderCode.CONTENT_TYPE,"application/json"); - build.header(HTTPHeaderCode.DATE, printDate); - build.sendWithEOM(); - } - - void plaintext() - { - auto build = scoped!ResponseBuilder(_downstream); - build.status(200,HTTPMessage.statusText(200)); - build.setBody(cast(ubyte[])"Hello, World!"); - build.header(HTTPHeaderCode.CONTENT_TYPE,"text/plain"); - build.header(HTTPHeaderCode.DATE, printDate); - build.sendWithEOM(); - } -} - diff --git a/frameworks/D/collie/source/request.d b/frameworks/D/collie/source/request.d deleted file mode 100644 index d3dec5d2251..00000000000 --- a/frameworks/D/collie/source/request.d +++ /dev/null @@ -1,65 +0,0 @@ -module request; - -import collie.codec.http; -import collie.codec.http.server; -import std.exception; -import std.datetime; -import std.conv; -import std.string; -import kiss.container.Vector; - -abstract class BaseHandler : RequestHandler -{ - alias Buffer = Vector!(ubyte); -protected: - final override void onResquest(HTTPMessage headers) nothrow - { - _header = headers; - } - - final override void onBody(const ubyte[] data) nothrow - { - collectException(_buffer.put(data)); - } - - final override void onError(HTTPErrorCode code) nothrow { - _erroCode = code; - collectException({ - import collie.utils.memory; - if(_header)gcFree(_header); - gcFree(this); - }()); - } - - final override void requestComplete() nothrow - { - _erroCode = HTTPErrorCode.REMOTE_CLOSED; - collectException({ - import collie.utils.memory; - if(_header)gcFree(_header); - gcFree(this); - }()); - } - - final @property bool isVaild(){return _erroCode == HTTPErrorCode.NO_ERROR;} - - pragma(inline) - final string printDate() { - DateTime date = cast(DateTime)Clock.currTime; - return format( - "%.3s, %02d %.3s %d %02d:%02d:%02d GMT", // could be UTC too - to!string(date.dayOfWeek).capitalize, - date.day, - to!string(date.month).capitalize, - date.year, - date.hour, - date.minute, - date.second); - } - -protected: - HTTPMessage _header; - Buffer _buffer; -private: - HTTPErrorCode _erroCode = HTTPErrorCode.NO_ERROR; -} diff --git a/frameworks/D/juptune/benchmark_config.json b/frameworks/D/juptune/benchmark_config.json index 0a091dc9fa6..6fd50cf6e8c 100755 --- a/frameworks/D/juptune/benchmark_config.json +++ b/frameworks/D/juptune/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "juptune", + "maintainers": ["BradleyChatha"], "tests": [ { "default": { @@ -19,7 +20,8 @@ "database_os": "Linux", "display_name": "Juptune", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] } } ] diff --git a/frameworks/D/juptune/juptune.dockerfile b/frameworks/D/juptune/juptune.dockerfile index 0a671e08d8d..2108e69394d 100644 --- a/frameworks/D/juptune/juptune.dockerfile +++ b/frameworks/D/juptune/juptune.dockerfile @@ -1,30 +1,36 @@ -FROM debian:bookworm-slim +FROM debian:bookworm ARG LDC_VERSION=1.41.0 -ARG JUPTUNE_REF=52294fa45912dacac24efc80b4a2fad8db958841 -ARG TFB_TEST_NAME - -ENV TEST_NAME=${TFB_TEST_NAME} +ARG JUPTUNE_REF=1b012d22d4e5e29e88fdf760be4cfa899ce3dfb2 # Install system deps & LDC RUN apt update \ - && apt install -y curl xz-utils gnupg libsodium-dev meson unzip pkg-config \ + && apt install -y curl xz-utils gnupg libsodium-dev meson unzip pkg-config clang cmake libssl-dev \ && curl -fsS https://dlang.org/install.sh | bash -s ldc-${LDC_VERSION} -# Install Juptune +# Install Juptune (Bookworm's meson is kind of old so we have to rename meson.options, +# and some of the dependencies are older than what Juptune targets, but downgrading is fine for the benchmark's code.) +# +# I'm also trying to dummy out some executables from being built so the entire thing builds faster... need to add an option upstream to make that better. WORKDIR /juptune RUN curl -fsSL https://github.com/Juptune/juptune/archive/${JUPTUNE_REF}.zip -o code.zip \ && unzip code.zip \ && cd juptune* \ && . ~/dlang/ldc-${LDC_VERSION}/activate \ - && meson setup build --buildtype debugoptimized -Ddefault_library=static \ + && mv meson.options meson_options.txt \ + && sed -i 's/1.0.20/1.0.18/' meson.build \ + && sed -i 's/3.5.0/1.0.18/' meson.build \ + && sed -iE "s|.+./examples|#|" meson.build \ + && sed -iE "s|^subdir|#|" meson.build \ + && sed -iEz 's|juptune_all_unittest_exe[^)]+)|#|' meson.build \ + && meson setup build --buildtype release -Dlightweight-results=true -Ddefault_library=static \ && meson install -C build # Compile everything WORKDIR /app COPY ./src/ . RUN . ~/dlang/ldc-${LDC_VERSION}/activate \ - && meson setup build --buildtype debugoptimized -Ddefault_library=static \ + && meson setup build --buildtype release -Ddefault_library=static \ && meson compile -C build ENTRYPOINT [ "/app/build/juptune-tfb" ] \ No newline at end of file diff --git a/frameworks/D/juptune/src/meson.build b/frameworks/D/juptune/src/meson.build index e4feb4ac896..ba69f5fd615 100644 --- a/frameworks/D/juptune/src/meson.build +++ b/frameworks/D/juptune/src/meson.build @@ -19,6 +19,10 @@ dep = declare_dependency( include_directories: include_directories('.'), sources: srcs, dependencies: [juptune_dep], + d_module_versions: [ + 'Juptune_Result_NoLineInfo', + 'Juptune_Result_NoContext' + ] ) #### Executables #### diff --git a/frameworks/D/juptune/src/tests/json.d b/frameworks/D/juptune/src/tests/json.d index cb363d7939c..66bc71fdbad 100644 --- a/frameworks/D/juptune/src/tests/json.d +++ b/frameworks/D/juptune/src/tests/json.d @@ -2,6 +2,7 @@ module tests.json; import juptune.core.ds : ArrayNonShrink; import juptune.core.util : Result; +import juptune.data.json : Json; import juptune.http : Http1Writer, Http1Version, Http1MessageSummary; import tests.common : putServerAndDate, log; @@ -13,7 +14,7 @@ struct JsonHeaderInput private struct Message { - string message; + @Json string message; } void handleJson( @@ -25,10 +26,16 @@ void handleJson( import juptune.core.util : then; import juptune.core.util.conv : IntToCharBuffer, toBase10; + import juptune.data.json : JsonBuilder, jsonSerialise; + ArrayNonShrink!char buffer; buffer.reserve(256); - auto result = serialise(buffer, Message("Hello, World!")); + ubyte[8] jsonDepth; + scope put = (scope const(char)[] slice) { buffer.put(slice); return Result.noError; }; + scope builder = JsonBuilder!(typeof(put))(put, jsonDepth); + + auto result = builder.jsonSerialise(Message("Hello, World!")); if(result.isError) { result = writer.putResponseLine(Http1Version.http11, 500, "Internal Error").then!( @@ -66,38 +73,4 @@ void handleJson( log("writing response [json] failed: ", result); return; } -} - -// There's currently no built-in serialiser, however because of D's incredibly powerful metaprogramming -// this watered-down serialiser would likely generate almost the exact same code as a full-blown serialiser -// in this simple case. -private Result serialise(T)(scope ref ArrayNonShrink!char buffer, T value) -if(is(T == struct)) -{ - import juptune.data.json : JsonBuilder; - scope append = (scope const(char)[] text) { - buffer.put(text); - return Result.noError; - }; - - ubyte[8] depthBuffer; - auto builder = JsonBuilder!(typeof(append))(append, depthBuffer[]); - - auto result = builder.startObject(); - if(result.isError) - return result; - - static foreach(fieldSymbol; value.tupleof) - {{ - immutable FieldName = __traits(identifier, fieldSymbol); - - result = builder.putObjectValue(FieldName, mixin("value."~FieldName)); - if(result.isError) - return result; - }} - - result = builder.endObject(); - if(result.isError) - return result; - return builder.finish(); } \ No newline at end of file diff --git a/frameworks/Dart/dart/README.md b/frameworks/Dart/dart/README.md deleted file mode 100644 index 78147e92537..00000000000 --- a/frameworks/Dart/dart/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Dart Benchmarking Test - -This is the dart portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -## Versions - -* [Dart SDK version >=1.6.0](https://dart.dev/) -* [Dart args version 0.12.0+2](https://pub.dev/packages/args) -* [Dart crypto version 0.9.0](https://pub.dev/packages/crypto) -* [Dart mustache version 0.1.8](https://pub.dev/packages/mustache) -* [Dart postgresql version 0.2.14](https://pub.dev/packages/postgresql) -* [Dart yaml version 2.0.1+1](https://pub.dev/packages/yaml) - -## Test URLs - -### JSON Encoding Test - -http://localhost:8080/ - -### Data-Store/Database Mapping Test - -http://localhost:8080/db - -### Variable Query Test - -http://localhost:8080/db?queries=2 - -### Fortunes Test - -http://localhost:8080/fortunes - -### Data-Store/Database Update Test - -http://localhost:8080/update - -### Variable Update Test - -http://localhost:8080/update?queries=2 - -### Plaintext Test - -http://localhost:8080/plaintext diff --git a/frameworks/Dart/dart/benchmark_config.json b/frameworks/Dart/dart/benchmark_config.json deleted file mode 100644 index 63bb79b8590..00000000000 --- a/frameworks/Dart/dart/benchmark_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "framework": "dart", - "tests": [{ - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Stripped", - "classification": "Platform", - "database": "Postgres", - "framework": "None", - "language": "Dart", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "dart", - "notes": "", - "versus": "dart" - } - }] -} diff --git a/frameworks/Dart/dart/config.toml b/frameworks/Dart/dart/config.toml deleted file mode 100644 index 1821542fc4a..00000000000 --- a/frameworks/Dart/dart/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "dart" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Stripped" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "dart" diff --git a/frameworks/Dart/dart/dart.dockerfile b/frameworks/Dart/dart/dart.dockerfile deleted file mode 100644 index bead7fc2ee5..00000000000 --- a/frameworks/Dart/dart/dart.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM google/dart:1.24 - -WORKDIR /dart_app -COPY fortunes.mustache fortunes.mustache -COPY postgresql.yaml postgresql.yaml -COPY pubspec.yaml pubspec.yaml -COPY server.dart server.dart - -RUN pub upgrade - -EXPOSE 8080 - -CMD ["dart", "server.dart"] diff --git a/frameworks/Dart/dart/fortunes.mustache b/frameworks/Dart/dart/fortunes.mustache deleted file mode 100644 index 77ea1a96cf5..00000000000 --- a/frameworks/Dart/dart/fortunes.mustache +++ /dev/null @@ -1,20 +0,0 @@ - - - - Fortunes - - - - - - - - {{#fortunes}} - - - - - {{/fortunes}} -
idmessage
{{id}}{{message}}
- - diff --git a/frameworks/Dart/dart/postgresql.yaml b/frameworks/Dart/dart/postgresql.yaml deleted file mode 100644 index b57e64ef9be..00000000000 --- a/frameworks/Dart/dart/postgresql.yaml +++ /dev/null @@ -1,5 +0,0 @@ -host: tfb-database -port: 5432 -user: benchmarkdbuser -password: benchmarkdbpass -database: hello_world diff --git a/frameworks/Dart/dart/pubspec.yaml b/frameworks/Dart/dart/pubspec.yaml deleted file mode 100644 index ff66f5f1abb..00000000000 --- a/frameworks/Dart/dart/pubspec.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: dartbenchmark -description: A benchmark of dart -environment: - sdk: '>=1.6.0 <2.0.0' -dependencies: - crypto: 0.9.0 - mustache: 0.1.8 - postgresql: 0.2.14 - system_info: 0.0.16 - yaml: 2.0.1+1 diff --git a/frameworks/Dart/dart/server.dart b/frameworks/Dart/dart/server.dart deleted file mode 100644 index fb8e487d1f8..00000000000 --- a/frameworks/Dart/dart/server.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'dart:async' show Future; -import 'dart:convert'; -import 'dart:io'; -import 'dart:isolate'; -import 'dart:math' show Random, max; -import 'package:mustache/mustache.dart' as mustache; -import 'package:postgresql/postgresql.dart' as pg; -import 'package:postgresql/postgresql_pool.dart' as pgpool; -import 'package:system_info/system_info.dart'; -import 'package:yaml/yaml.dart' as yaml; - -final _NUM_PROCESSORS = SysInfo.processors.length; - -final _encoder = new JsonUtf8Encoder(); - -void main(List args) { - ReceivePort errorPort = new ReceivePort(); - errorPort.listen((e) => print(e)); - for (int i = 0; i < _NUM_PROCESSORS; i++) { - Isolate.spawn( - startInIsolate, - [], - onError: errorPort.sendPort); - } -} - -void startInIsolate(List args) { - _startServer(); -} - -/// The entity used in the database query and update tests. -class World { - int id; - - int randomnumber; - - World(this.id, this.randomnumber); - - toJson() => {'id': id, 'randomNumber': randomnumber}; -} - -/// The entity used in the fortunes test. -class Fortune implements Comparable { - int id; - String message; - - Fortune(this.id, this.message); - - int compareTo(Fortune other) => message.compareTo(other.message); -} - -/// The number of rows in the world entity table. -const _WORLD_TABLE_SIZE = 10000; - -/// A random number generator. -final _RANDOM = new Random(); - -/// The PostgreSQL connection pool used by all the tests that require database -/// connectivity. -pgpool.Pool _connectionPool; - -/// The mustache template which is rendered in the fortunes test. -mustache.Template _fortunesTemplate; - -void _startServer() { - var dbConnections = max(1, (256 / _NUM_PROCESSORS).floor()); - Future.wait([ - HttpServer.bind("0.0.0.0", 8080, shared: true), - new File('postgresql.yaml').readAsString().then((config) { - _connectionPool = new pgpool.Pool( - new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(), - min: dbConnections, max: dbConnections); - return _connectionPool.start(); - }), - new File('fortunes.mustache').readAsString().then((template) { - _fortunesTemplate = mustache.parse(template); - }) - ]).then((List waitResults) { - var server = waitResults[0]; - server.defaultResponseHeaders.clear(); - server.serverHeader = 'dart'; - server.listen((request) { - switch (request.uri.path) { - case '/json': - _jsonTest(request); - break; - case '/db': - _dbTest(request); - break; - case '/queries': - _queriesTest(request); - break; - case '/fortunes': - _fortunesTest(request); - break; - case '/updates': - _updatesTest(request); - break; - case '/plaintext': - _plaintextTest(request); - break; - default: - _sendResponse(request, HttpStatus.NOT_FOUND); - break; - } - }); - }); -} - -/// Returns the given [text] parsed as a base 10 integer. If the text is null -/// or is an otherwise invalid representation of a base 10 integer, zero is -/// returned. -int _parseInt(String text) => - (text == null) ? 0 : int.parse(text, radix: 10, onError: ((_) => 0)); - -/// Completes the given [request] by writing the [response] with the given -/// [statusCode] and [type]. -void _sendResponse(HttpRequest request, int statusCode, - {ContentType type, List response}) { - request.response.statusCode = statusCode; - request.response.headers.date = new DateTime.now(); - if (type != null) { - request.response.headers.contentType = type; - } - if (response != null) { - request.response.contentLength = response.length; - request.response.add(response); - } else { - request.response.contentLength = 0; - } - request.response.close(); -} - -/// Completes the given [request] by writing the [response] as HTML. -void _sendHtml(HttpRequest request, String response) { - _sendResponse(request, HttpStatus.OK, - type: ContentType.HTML, response: UTF8.encode(response)); -} - -/// Completes the given [request] by writing the [response] as JSON. -void _sendJson(HttpRequest request, Object response) { - _sendResponse(request, HttpStatus.OK, - type: ContentType.JSON, response: _encoder.convert(response)); -} - -/// Completes the given [request] by writing the [response] as plain text. -void _sendText(HttpRequest request, String response) { - _sendResponse(request, HttpStatus.OK, - type: ContentType.TEXT, response: UTF8.encode(response)); -} - -/// Responds with the JSON test to the [request]. -void _jsonTest(HttpRequest request) { - _sendJson(request, {'message': 'Hello, World!'}); -} - -Future _queryRandom() { - return _connectionPool.connect().then((connection) { - return connection.query( - 'SELECT id, randomnumber FROM world WHERE id = @id;', { - 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 - }) - // - // The benchmark's constraints tell us there is exactly one row. - // - .single.then((row) => new World(row[0], row[1])).whenComplete(() { - connection.close(); - }); - }); -} - -/// Responds with the database query test to the [request]. -void _dbTest(HttpRequest request) { - _queryRandom().then((response) => _sendJson(request, response)); -} - -/// Responds with the database queries test to the [request]. -void _queriesTest(HttpRequest request) { - var queries = _parseInt(request.uri.queryParameters['queries']).clamp(1, 500); - Future - .wait(new List.generate(queries, (_) => _queryRandom(), growable: false)) - .then((response) => _sendJson(request, response)); -} - -/// Responds with the fortunes test to the [request]. -void _fortunesTest(HttpRequest request) { - _connectionPool.connect().then((connection) { - return connection - .query('SELECT id, message FROM fortune;') - .map((row) => new Fortune(row[0], row[1])) - .toList() - .whenComplete(() { - connection.close(); - }); - }).then((fortunes) { - fortunes.add(new Fortune(0, 'Additional fortune added at request time.')); - fortunes.sort(); - _sendHtml(request, _fortunesTemplate.renderString({ - 'fortunes': fortunes - .map((fortune) => {'id': fortune.id, 'message': fortune.message}) - .toList() - })); - }); -} - -/// Responds with the updates test to the [request]. -void _updatesTest(HttpRequest request) { - var queries = _parseInt(request.uri.queryParameters['queries']).clamp(1, 500); - Future.wait(new List.generate(queries, (_) { - return _queryRandom().then((world) { - world.randomnumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1; - return _connectionPool.connect().then((connection) { - return connection - .execute( - 'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;', - {'randomnumber': world.randomnumber, 'id': world.id}) - .whenComplete(() { - connection.close(); - }); - }).then((_) => world); - }); - }, growable: false)).then((worlds) => _sendJson(request, worlds)); -} - -/// Responds with the plaintext test to the [request]. -void _plaintextTest(HttpRequest request) { - _sendText(request, 'Hello, World!'); -} diff --git a/frameworks/Dart/dart3/.gitignore b/frameworks/Dart/dart3/.gitignore index 27fe9f77a4b..a4aa0af72a0 100644 --- a/frameworks/Dart/dart3/.gitignore +++ b/frameworks/Dart/dart3/.gitignore @@ -1,5 +1,3 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` .dart_tool/ *.lock -!bin +!bin \ No newline at end of file diff --git a/frameworks/Dart/dart3/README.md b/frameworks/Dart/dart3/README.md index 7152e705637..3be261226e2 100644 --- a/frameworks/Dart/dart3/README.md +++ b/frameworks/Dart/dart3/README.md @@ -1,22 +1,31 @@ # Dart 3 Benchmarking Test -### Test Type Implementation Source Code - -- [JSON](server.dart) -- [PLAINTEXT](server.dart) - ## Important Libraries The tests were run with: -- [Dart v3.4.4](https://dart.dev/) +- [Dart v3.11.0](https://dart.dev/) + +## Benchmark Variants + +### Native + +Minimal implementation with the smallest resource footprint. +Supports basic horizontal scaling via [Isolates](https://dart.dev/language/isolates) and socket sharing. +([source code](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Dart/dart3/dart_native)) + +Test URLs: -## Test URLs +- JSON: `http://localhost:8080/json` +- PLAINTEXT: `http://localhost:8080/plaintext` -### JSON +### AOT -http://localhost:8080/json +Performance-oriented AOT implementation for superior horizontal scaling. +Achieves lowest latency and higher throughput with a slightly larger footprint. +([source code](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Dart/dart3/dart_aot)) -### PLAINTEXT +Test URLs: -http://localhost:8080/plaintext +- JSON: `http://localhost:8080/json` +- PLAINTEXT: `http://localhost:8080/plaintext` diff --git a/frameworks/Dart/dart3/analysis_options.yaml b/frameworks/Dart/dart3/analysis_options.yaml index 572dd239d09..926fdf8d193 100644 --- a/frameworks/Dart/dart3/analysis_options.yaml +++ b/frameworks/Dart/dart3/analysis_options.yaml @@ -1 +1,3 @@ include: package:lints/recommended.yaml +formatter: + trailing_commas: preserve diff --git a/frameworks/Dart/dart3/benchmark_config.json b/frameworks/Dart/dart3/benchmark_config.json index 059fb368d0e..2b3d7df97e1 100644 --- a/frameworks/Dart/dart3/benchmark_config.json +++ b/frameworks/Dart/dart3/benchmark_config.json @@ -1,26 +1,30 @@ { "framework": "dart3", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Stripped", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "Dart", - "flavor": "None", - "orm": "None", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "dart3", - "notes": "", - "versus": "None" - } + "maintainers": ["iapicca"], + "tests": [{ + "default": { + "display_name": "dart3_native", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Stripped", + "classification": "Platform", + "database": "None", + "language": "Dart", + "os": "Linux", + "database_os": "Linux" + }, + "aot": { + "display_name": "dart3_aot", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Stripped", + "classification": "Platform", + "database": "None", + "language": "Dart", + "os": "Linux", + "database_os": "Linux" } - ] -} + }] +} \ No newline at end of file diff --git a/frameworks/Dart/dart3/bin/server.dart b/frameworks/Dart/dart3/bin/server.dart deleted file mode 100755 index 5859cc51f82..00000000000 --- a/frameworks/Dart/dart3/bin/server.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:isolate'; - -void main(List args) async { - /// Create an [Isolate] containing an [HttpServer] - /// for each processor after the first - for (var i = 1; i < Platform.numberOfProcessors; i++) { - await Isolate.spawn(_startServer, args); - } - - /// Create a [HttpServer] for the first processor - await _startServer(args); -} - -/// Creates and setup a [HttpServer] -Future _startServer(List _) async { - /// Binds the [HttpServer] on `0.0.0.0:8080`. - final server = await HttpServer.bind( - InternetAddress.anyIPv4, - 8080, - shared: true, - ); - - /// Sets [HttpServer]'s [serverHeader]. - server - ..defaultResponseHeaders.clear() - ..serverHeader = 'dart'; - - /// Handles [HttpRequest]'s from [HttpServer]. - await for (final request in server) { - switch (request.uri.path) { - case '/json': - _jsonTest(request); - break; - case '/plaintext': - _plaintextTest(request); - break; - default: - _sendResponse(request, HttpStatus.notFound); - } - } -} - -/// Completes the given [request] by writing the [bytes] with the given -/// [statusCode] and [type]. -void _sendResponse( - HttpRequest request, - int statusCode, { - ContentType? type, - List bytes = const [], -}) => request.response - ..statusCode = statusCode - ..headers.contentType = type - ..headers.date = DateTime.now() - ..contentLength = bytes.length - ..add(bytes) - ..close(); - -/// Completes the given [request] by writing the [response] as JSON. -void _sendJson(HttpRequest request, Object response) => _sendResponse( - request, - HttpStatus.ok, - type: ContentType.json, - bytes: _jsonEncoder.convert(response), -); - -/// Completes the given [request] by writing the [response] as plain text. -void _sendText(HttpRequest request, String response) => _sendResponse( - request, - HttpStatus.ok, - type: ContentType.text, - bytes: utf8.encode(response), -); - -/// Responds with the JSON test to the [request]. -void _jsonTest(HttpRequest request) => - _sendJson(request, const {'message': 'Hello, World!'}); - -/// Responds with the plaintext test to the [request]. -void _plaintextTest(HttpRequest request) => _sendText(request, 'Hello, World!'); - -final _jsonEncoder = JsonUtf8Encoder(); diff --git a/frameworks/Dart/dart3/dart3-aot.dockerfile b/frameworks/Dart/dart3/dart3-aot.dockerfile new file mode 100644 index 00000000000..ef9d633eadf --- /dev/null +++ b/frameworks/Dart/dart3/dart3-aot.dockerfile @@ -0,0 +1,22 @@ + +FROM dart:3.11.0 AS build +WORKDIR /app + +ARG MAX_ISOLATES=8 + +COPY pubspec.yaml . +COPY dart_aot/bin/ bin/ + +RUN dart compile aot-snapshot bin/server.dart \ + --define=MAX_ISOLATES=${MAX_ISOLATES} \ + -o server.aot + +FROM gcr.io/distroless/base-debian13 +WORKDIR /app + +COPY --from=build /usr/lib/dart/bin/dartaotruntime /usr/lib/dart/bin/dartaotruntime +COPY --from=build /app/server.aot /app/server.aot + +EXPOSE 8080 + +ENTRYPOINT ["/usr/lib/dart/bin/dartaotruntime", "/app/server.aot"] diff --git a/frameworks/Dart/dart3/dart3.dockerfile b/frameworks/Dart/dart3/dart3.dockerfile index 812b7e959ee..6b9a5b82753 100644 --- a/frameworks/Dart/dart3/dart3.dockerfile +++ b/frameworks/Dart/dart3/dart3.dockerfile @@ -1,14 +1,15 @@ -FROM dart:3.8 AS builder - -COPY . /app +FROM dart:3.11.0 AS build WORKDIR /app -RUN mkdir build -RUN dart compile exe ./bin/server.dart -o build/server + +COPY pubspec.yaml . +COPY dart_native/bin/ bin/ + +RUN dart compile exe bin/server.dart -o server FROM scratch -COPY --from=builder /runtime/ / -COPY --from=builder /app/build /bin +COPY --from=build /runtime/ / +COPY --from=build /app/server /bin/server EXPOSE 8080 -CMD ["server"] +ENTRYPOINT ["server"] \ No newline at end of file diff --git a/frameworks/Dart/dart3/dart_aot/bin/server.dart b/frameworks/Dart/dart3/dart_aot/bin/server.dart new file mode 100755 index 00000000000..4b0f1064942 --- /dev/null +++ b/frameworks/Dart/dart3/dart_aot/bin/server.dart @@ -0,0 +1,167 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math' show min; + +/// Environment declarations are evaluated at compile-time. Use 'const' to +/// ensure values are baked into AOT/Native binaries for the benchmark. +/// +/// From https://api.dart.dev/dart-core/int/int.fromEnvironment.html: +/// "This constructor is only guaranteed to work when invoked as const. +/// It may work as a non-constant invocation on some platforms +/// which have access to compiler options at run-time, +/// but most ahead-of-time compiled platforms will not have this information." +const _maxIsolatesfromEnvironment = int.fromEnvironment('MAX_ISOLATES'); + +/// The fixed TCP port used by the server. +/// Defined here for visibility and ease of configuration. +const _defaultPort = 8080; + +/// A reusable instance of the UTF-8 JSON encoder to efficiently +/// transform Dart objects into byte arrays for HTTP responses. +final _jsonEncoder = JsonUtf8Encoder(); + +/// Internal token used to notify newly spawned processes that they +/// belong to a secondary "worker group". +const _workerGroupTag = '--WORKER-GROUP'; + +/// The maximum duration allowed for a single HTTP request to be processed. +/// This prevents slow clients or stalled logic from blocking the isolate's +/// event loop indefinitely. +const _requestTimeout = Duration(seconds: 8); + +void main(List arguments) async { + /// Create a mutable copy of the fixed-length arguments list. + final args = [...arguments]; + + /// Defines local isolate quota, using MAX_ISOLATES if provided. + /// Falls back to total available cores while respecting hardware limits. + var maxIsolates = _maxIsolatesfromEnvironment > 0 + ? min(_maxIsolatesfromEnvironment, Platform.numberOfProcessors) + : Platform.numberOfProcessors; + + /// Determine if this process instance was initialized as a worker group. + if (args.contains(_workerGroupTag)) { + /// Sanitize the argument list to ensure the internal token does not + /// interfere with application-level argument parsing. + args.remove(_workerGroupTag); + } + /// Prevents recursive spawning + /// by ensuring only the primary process can spawn worker groups + else { + /// Calculate the number of secondary worker groups required + /// to fully utilize the available hardware capacity. + /// + /// Each group serves as a container for multiple isolates, + /// helping to bypass internal VM scaling bottlenecks. + final workerGroups = Platform.numberOfProcessors ~/ maxIsolates - 1; + + /// Bootstraps independent worker processes via AOT snapshots. + /// Each process initializes its own Isolate Group. + for (var i = 0; i < workerGroups; i++) { + /// [Platform.script] identifies the AOT snapshot or executable. + /// [Isolate.spawnUri] spawns a new process group via [main()]. + await Isolate.spawnUri(Platform.script, [...args, _workerGroupTag], null); + } + + /// Updates local isolate limits, assigning the primary group + /// the remaining cores after worker group allocation. + maxIsolates = Platform.numberOfProcessors - workerGroups * maxIsolates; + } + + /// Create an [Isolate] containing an [HttpServer] + /// for each processor after the first + for (var i = 1; i < maxIsolates; i++) { + await Isolate.spawn(_startServer, args); + } + + /// Create a [HttpServer] for the first processor + await _startServer(args); +} + +/// Creates and setup a [HttpServer] +Future _startServer(List args) async { + /// Binds the [HttpServer] on `0.0.0.0:8080`. + final server = await HttpServer.bind( + InternetAddress.anyIPv4, + _defaultPort, + shared: true, + ); + + server + ..defaultResponseHeaders.clear() + /// Sets [HttpServer]'s [serverHeader]. + ..serverHeader = 'dart_aot'; + + /// Handles [HttpRequest]'s from [HttpServer]. + await for (final request in server) { + /// Asynchronously processes each request with an 8-second safety deadline + /// to prevent stalled connections from blocking the isolate event loop. + await _handleRequest(request).timeout( + _requestTimeout, + onTimeout: () => _sendResponse(request, HttpStatus.requestTimeout), + ); + } +} + +/// Dispatches requests to specific test handlers. Wrapped in a try-catch +/// to ensure stable execution and guaranteed response delivery. +Future _handleRequest(HttpRequest request) async { + try { + switch (request.uri.path) { + case '/json': + _jsonTest(request); + break; + case '/plaintext': + _plaintextTest(request); + break; + default: + _sendResponse(request, HttpStatus.notFound); + } + } catch (e) { + _sendResponse(request, HttpStatus.internalServerError); + } +} + +/// Completes the given [request] by writing the [bytes] with the given +/// [statusCode] and [type]. +void _sendResponse( + HttpRequest request, + int statusCode, { + ContentType? type, + List bytes = const [], +}) => request.response + ..statusCode = statusCode + ..headers.contentType = type + ..headers.date = DateTime.now() + ..contentLength = bytes.length + ..add(bytes) + ..close(); + +/// Completes the given [request] by writing the [response] as JSON. +void _sendJson(HttpRequest request, Object response) => _sendResponse( + request, + HttpStatus.ok, + type: ContentType.json, + bytes: _jsonEncoder.convert(response), +); + +/// Completes the given [request] by writing the [response] as plain text. +void _sendText(HttpRequest request, String response) => _sendResponse( + request, + HttpStatus.ok, + type: ContentType.text, + bytes: utf8.encode(response), +); + +/// Responds with the JSON test to the [request]. +void _jsonTest(HttpRequest request) => _sendJson( + request, + const {'message': 'Hello, World!'}, +); + +/// Responds with the plaintext test to the [request]. +void _plaintextTest(HttpRequest request) => _sendText( + request, + 'Hello, World!', +); diff --git a/frameworks/Dart/dart3/dart_native/bin/server.dart b/frameworks/Dart/dart3/dart_native/bin/server.dart new file mode 100755 index 00000000000..029c6eaee1d --- /dev/null +++ b/frameworks/Dart/dart3/dart_native/bin/server.dart @@ -0,0 +1,114 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; + +/// The fixed TCP port used by the server. +/// Defined here for visibility and ease of configuration. +const _defaultPort = 8080; + +/// A reusable instance of the UTF-8 JSON encoder to efficiently +/// transform Dart objects into byte arrays for HTTP responses. +final _jsonEncoder = JsonUtf8Encoder(); + +/// The maximum duration allowed for a single HTTP request to be processed. +/// This prevents slow clients or stalled logic from blocking the isolate's +/// event loop indefinitely. +const _requestTimeout = Duration(seconds: 8); + +void main(List args) async { + /// Create an [Isolate] containing an [HttpServer] + /// for each processor after the first + for (var i = 1; i < Platform.numberOfProcessors; i++) { + await Isolate.spawn(_startServer, args); + } + + /// Create a [HttpServer] for the first processor + await _startServer(args); +} + +/// Creates and setup a [HttpServer] +Future _startServer(List args) async { + /// Binds the [HttpServer] on `0.0.0.0:8080`. + final server = await HttpServer.bind( + InternetAddress.anyIPv4, + _defaultPort, + shared: true, + ); + + server + ..defaultResponseHeaders.clear() + /// Sets [HttpServer]'s [serverHeader]. + ..serverHeader = 'dart_native'; + + /// Handles [HttpRequest]'s from [HttpServer]. + await for (final request in server) { + /// Asynchronously processes each request with an 8-second safety deadline + /// to prevent stalled connections from blocking the isolate event loop. + await _handleRequest(request).timeout( + _requestTimeout, + onTimeout: () => _sendResponse(request, HttpStatus.requestTimeout), + ); + } +} + +/// Dispatches requests to specific test handlers. Wrapped in a try-catch +/// to ensure stable execution and guaranteed response delivery. +Future _handleRequest(HttpRequest request) async { + try { + switch (request.uri.path) { + case '/json': + _jsonTest(request); + break; + case '/plaintext': + _plaintextTest(request); + break; + default: + _sendResponse(request, HttpStatus.notFound); + } + } catch (e) { + _sendResponse(request, HttpStatus.internalServerError); + } +} + +/// Completes the given [request] by writing the [bytes] with the given +/// [statusCode] and [type]. +void _sendResponse( + HttpRequest request, + int statusCode, { + ContentType? type, + List bytes = const [], +}) => request.response + ..statusCode = statusCode + ..headers.contentType = type + ..headers.date = DateTime.now() + ..contentLength = bytes.length + ..add(bytes) + ..close(); + +/// Completes the given [request] by writing the [response] as JSON. +void _sendJson(HttpRequest request, Object response) => _sendResponse( + request, + HttpStatus.ok, + type: ContentType.json, + bytes: _jsonEncoder.convert(response), +); + +/// Completes the given [request] by writing the [response] as plain text. +void _sendText(HttpRequest request, String response) => _sendResponse( + request, + HttpStatus.ok, + type: ContentType.text, + bytes: utf8.encode(response), +); + +/// Responds with the JSON test to the [request]. +void _jsonTest(HttpRequest request) => _sendJson( + request, + const {'message': 'Hello, World!'}, +); + +/// Responds with the plaintext test to the [request]. +void _plaintextTest(HttpRequest request) => _sendText( + request, + 'Hello, World!', +); diff --git a/frameworks/Dart/dart3/pubspec.yaml b/frameworks/Dart/dart3/pubspec.yaml index 5a99e258055..aeb53912216 100644 --- a/frameworks/Dart/dart3/pubspec.yaml +++ b/frameworks/Dart/dart3/pubspec.yaml @@ -1,7 +1,8 @@ name: dartbenchmark description: A benchmark of dart environment: - sdk: ^3.8.0 + sdk: ^3.11.0 dev_dependencies: - lints: ^4.0.0 + lints: ^6.1.0 + diff --git a/frameworks/Dart/dart_frog/dart_frog.dockerfile b/frameworks/Dart/dart_frog/dart_frog.dockerfile index 345f891c6db..2663ef90f6d 100644 --- a/frameworks/Dart/dart_frog/dart_frog.dockerfile +++ b/frameworks/Dart/dart_frog/dart_frog.dockerfile @@ -1,4 +1,4 @@ -FROM dart:3.8 AS builder +FROM dart:3.11 AS builder COPY . /app WORKDIR /app @@ -10,7 +10,7 @@ RUN dart compile exe build/bin/server.dart -o build/bin/server FROM scratch COPY --from=builder /runtime/ / -COPY --from=builder /app/build/bin/server /app/build/bin/ +COPY --from=builder /app/build/bin/server /bin/server EXPOSE 8080 -CMD ["/app/build/bin/server"] +ENTRYPOINT ["server"] \ No newline at end of file diff --git a/frameworks/Dart/dart_frog/pubspec.yaml b/frameworks/Dart/dart_frog/pubspec.yaml index e521d43a053..79e023644e9 100644 --- a/frameworks/Dart/dart_frog/pubspec.yaml +++ b/frameworks/Dart/dart_frog/pubspec.yaml @@ -1,7 +1,7 @@ name: dartfrogbenchmark description: A benchmark of pkg:dart_frog environment: - sdk: ^3.8.0 + sdk: ^3.11.0 dependencies: - dart_frog: ^1.0.0 + dart_frog: ^1.2.6 diff --git a/frameworks/Dart/dia/README.md b/frameworks/Dart/dia/README.md deleted file mode 100755 index 9840bc7339b..00000000000 --- a/frameworks/Dart/dia/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Dia Benchmarking Test - -### Test Type Implementation Source Code - -* [JSON](src/server.dart) -* [PLAINTEXT](src/server.dart) - -## Important Libraries -The tests were run with: -* [Dart >=2.12.0 < 3.0.0](https://dart.dev) -* [Dia ^0.0.7](https://pub.dev/packages/dia) - -## Test URLs -### JSON - -http://localhost:8080/json - -### PLAINTEXT - -http://localhost:8080/plaintext diff --git a/frameworks/Dart/dia/benchmark_config.json b/frameworks/Dart/dia/benchmark_config.json deleted file mode 100755 index c8080800dbd..00000000000 --- a/frameworks/Dart/dia/benchmark_config.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "framework": "dia", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Dia", - "language": "Dart", - "flavor": "None", - "orm": "None", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Dia", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Dart/dia/dia.dockerfile b/frameworks/Dart/dia/dia.dockerfile deleted file mode 100644 index 2a33936bae5..00000000000 --- a/frameworks/Dart/dia/dia.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM google/dart:2.12 - -#ADD ./ /src -WORKDIR /src - -COPY src/pubspec.yaml pubspec.yaml -COPY src/server.dart server.dart - -RUN pub upgrade - -EXPOSE 8080 - -CMD ["dart", "server.dart"] diff --git a/frameworks/Dart/dia/src/.dart_tool/package_config.json b/frameworks/Dart/dia/src/.dart_tool/package_config.json deleted file mode 100644 index be14b332423..00000000000 --- a/frameworks/Dart/dia/src/.dart_tool/package_config.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "configVersion": 2, - "packages": [ - { - "name": "dia", - "rootUri": "file:///Users/duke/.pub-cache/hosted/pub.dartlang.org/dia-0.0.8", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "dia_router", - "rootUri": "file:///Users/duke/.pub-cache/hosted/pub.dartlang.org/dia_router-0.0.6", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "path_to_regexp", - "rootUri": "file:///Users/duke/.pub-cache/hosted/pub.dartlang.org/path_to_regexp-0.4.0", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "DiaBenchmark", - "rootUri": "../", - "packageUri": "lib/", - "languageVersion": "2.12" - } - ], - "generated": "2022-09-07T13:44:12.718551Z", - "generator": "pub", - "generatorVersion": "2.18.0" -} diff --git a/frameworks/Dart/dia/src/pubspec.lock b/frameworks/Dart/dia/src/pubspec.lock deleted file mode 100644 index 4fb8f74a2e9..00000000000 --- a/frameworks/Dart/dia/src/pubspec.lock +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - dia: - dependency: "direct main" - description: - name: dia - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.8" - dia_router: - dependency: "direct main" - description: - name: dia_router - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.6" - path_to_regexp: - dependency: transitive - description: - name: path_to_regexp - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.0" -sdks: - dart: ">=2.12.0 <3.0.0" diff --git a/frameworks/Dart/dia/src/pubspec.yaml b/frameworks/Dart/dia/src/pubspec.yaml deleted file mode 100644 index 528862f6816..00000000000 --- a/frameworks/Dart/dia/src/pubspec.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: DiaBenchmark -description: A benchmark of Dart Dia, a http simple framework -environment: - sdk: ">=2.12.0 <3.0.0" -dependencies: - dia: ^0.0.7 - dia_router: ^0.0.5 diff --git a/frameworks/Dart/dia/src/server.dart b/frameworks/Dart/dia/src/server.dart deleted file mode 100644 index 51593d09fec..00000000000 --- a/frameworks/Dart/dia/src/server.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:io'; - -import 'package:dia/dia.dart'; -import 'package:dia_router/dia_router.dart'; - -class CustomContext extends Context with Routing { - CustomContext(HttpRequest request) : super(request); -} - -void main() { - final app = App(); - - final router = Router('/'); - - app.use((ctx, next) async { - ctx.set('Server', 'Dia'); - ctx.set('Date', HttpDate.format(DateTime.now()).toString()); - await next(); - }); - - router.get('/plaintext', (ctx, next) async { - ctx.body = 'Hello, World!'; - }); - - router.get('/json', (ctx, next) async { - ctx.contentType = ContentType.json; - ctx.body = '{"message":"Hello, World!"}'; - }); - - app.use(router.middleware); - - /// Start server listen on localhsot:8080 - app - .listen('0.0.0.0', 8080) - .then((info) => print('Server started on http://0.0.0.0:8080')); -} diff --git a/frameworks/Dart/relic/analysis_options.yaml b/frameworks/Dart/relic/analysis_options.yaml new file mode 100644 index 00000000000..926fdf8d193 --- /dev/null +++ b/frameworks/Dart/relic/analysis_options.yaml @@ -0,0 +1,3 @@ +include: package:lints/recommended.yaml +formatter: + trailing_commas: preserve diff --git a/frameworks/Dart/relic/benchmark_config.json b/frameworks/Dart/relic/benchmark_config.json index 1f309015336..2b9f31c23be 100644 --- a/frameworks/Dart/relic/benchmark_config.json +++ b/frameworks/Dart/relic/benchmark_config.json @@ -20,6 +20,25 @@ "display_name": "relic", "notes": "", "versus": "None" + }, + "aot": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "relic", + "language": "Dart", + "flavor": "None", + "orm": "None", + "platform": "relic", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "relic_aot", + "notes": "", + "versus": "None" } } ] diff --git a/frameworks/Dart/relic/bin/server.dart b/frameworks/Dart/relic/bin/server.dart deleted file mode 100644 index b020cb396d4..00000000000 --- a/frameworks/Dart/relic/bin/server.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:isolate'; -import 'dart:typed_data'; - -import 'package:relic/io_adapter.dart'; -import 'package:relic/relic.dart'; - -void main() async { - /// Number of [Isolate]s to spawn - /// This is based on the number of available processors - /// minus one for the main isolate - final isolateCount = Platform.numberOfProcessors * 2 - 1; - - /// Create an [Isolate] containing an [HttpServer] - await Future.wait( - List.generate( - isolateCount, - (final index) => - Isolate.spawn((final _) => _serve(), null, debugName: '$index'), - ), - ); - - _serve(); -} - -/// [_serve] is called in each spawned isolate. -Future _serve() async { - final router = Router() - ..get('/json', respondWith((req) => _responseJson())) - ..get('/plaintext', respondWith((req) => _responsePlainText())); - - final handler = const Pipeline() - .addMiddleware(_requiredHeadersMiddleware()) - .addMiddleware(routeWith(router)) - .addHandler(respondWith((_) => Response.notFound())); - - // start the server - await serve(handler, InternetAddress.anyIPv4, 8080, shared: true); -} - -Middleware _requiredHeadersMiddleware() { - var addHeaders = createMiddleware( - onResponse: (response) => response.copyWith( - headers: response.headers.transform((headers) { - headers.server = 'relic'; - // Date header is added by default, but we set it here for clarity. - headers.date = DateTime.now(); - }), - ), - ); - return addHeaders; -} - -Response _responseJson() { - return Response.ok( - body: Body.fromData( - _jsonEncoder.convert(const {'message': 'Hello, World!'}) as Uint8List, - mimeType: MimeType.json, - ), - ); -} - -Response _responsePlainText() { - return Response.ok( - body: Body.fromString('Hello, World!', mimeType: MimeType.plainText), - ); -} - -final _jsonEncoder = JsonUtf8Encoder(); diff --git a/frameworks/Dart/relic/pubspec.yaml b/frameworks/Dart/relic/pubspec.yaml index a473d37b055..990a539a388 100644 --- a/frameworks/Dart/relic/pubspec.yaml +++ b/frameworks/Dart/relic/pubspec.yaml @@ -1,7 +1,10 @@ name: relicbenchmark description: A benchmark of pkg:relic environment: - sdk: ^3.8.0 + sdk: ^3.11.0 dependencies: - relic: ^0.7.0 + relic: ^1.1.1 + +dev_dependencies: + lints: ^6.1.0 \ No newline at end of file diff --git a/frameworks/Dart/relic/relic-aot.dockerfile b/frameworks/Dart/relic/relic-aot.dockerfile new file mode 100644 index 00000000000..c32dcac39ef --- /dev/null +++ b/frameworks/Dart/relic/relic-aot.dockerfile @@ -0,0 +1,22 @@ + +FROM dart:3.11.0 AS build +WORKDIR /app + +ARG MAX_ISOLATES=8 + +COPY pubspec.yaml . +COPY relic_aot/bin/ bin/ + +RUN dart compile aot-snapshot bin/server.dart \ + --define=MAX_ISOLATES=${MAX_ISOLATES} \ + -o server.aot + +FROM gcr.io/distroless/base-debian13 +WORKDIR /app + +COPY --from=build /usr/lib/dart/bin/dartaotruntime /usr/lib/dart/bin/dartaotruntime +COPY --from=build /app/server.aot /app/server.aot + +EXPOSE 8080 + +ENTRYPOINT ["/usr/lib/dart/bin/dartaotruntime", "/app/server.aot"] diff --git a/frameworks/Dart/relic/relic.dockerfile b/frameworks/Dart/relic/relic.dockerfile index 1671de7d052..0eb967736d6 100644 --- a/frameworks/Dart/relic/relic.dockerfile +++ b/frameworks/Dart/relic/relic.dockerfile @@ -1,14 +1,15 @@ -FROM dart:3.9 AS builder - -COPY . /app +FROM dart:3.11.0 AS build WORKDIR /app -RUN mkdir build -RUN dart compile exe ./bin/server.dart -o build/server + +COPY pubspec.yaml . +COPY relic_native/bin/ bin/ + +RUN dart compile exe bin/server.dart -o server FROM scratch -COPY --from=builder /runtime/ / -COPY --from=builder /app/build /bin +COPY --from=build /runtime/ / +COPY --from=build /app/server /bin/server EXPOSE 8080 -CMD ["server"] +ENTRYPOINT ["server"] \ No newline at end of file diff --git a/frameworks/Dart/relic/relic_aot/bin/server.dart b/frameworks/Dart/relic/relic_aot/bin/server.dart new file mode 100644 index 00000000000..c315aed9462 --- /dev/null +++ b/frameworks/Dart/relic/relic_aot/bin/server.dart @@ -0,0 +1,80 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math' show min; +import 'dart:typed_data'; + +import 'package:relic/relic.dart'; + +/// Fetches the 'MAX_ISOLATES' compile-time configuration. +const _maxIsolatesfromEnvironment = int.fromEnvironment('MAX_ISOLATES'); + +/// Internal token used to notify newly spawned processes. +const _workerGroupTag = '--WORKER-GROUP'; + +/// The fixed TCP port used by the server. +const _defaultPort = 8080; + +/// Reusable UTF-8 JSON encoder for efficient byte array transformations. +final _jsonEncoder = JsonUtf8Encoder(); + +void main(List args) async { + /// Defines local isolate quota, using MAX_ISOLATES if provided. + var maxIsolates = _maxIsolatesfromEnvironment > 0 + ? min(_maxIsolatesfromEnvironment, Platform.numberOfProcessors) + : Platform.numberOfProcessors; + + /// Determine if this process instance was initialized as a worker group. + if (!args.contains(_workerGroupTag)) { + /// Calculate the number of secondary worker groups required + final workerGroups = Platform.numberOfProcessors ~/ maxIsolates - 1; + + /// Bootstraps independent worker processes via AOT snapshots. + for (var i = 0; i < workerGroups; i++) { + await Isolate.spawnUri(Platform.script, [...args, _workerGroupTag], null); + } + + /// Updates local isolate limits, assigning the primary group + /// the remaining cores after worker group allocation. + maxIsolates = Platform.numberOfProcessors - workerGroups * maxIsolates; + } + + /// Entry point: starts the server utilizing available CPU cores. + await _app.serve( + address: InternetAddress.anyIPv4, + port: _defaultPort, + noOfIsolates: maxIsolates, + shared: true, // Allows isolates to share the same port. + ); +} + +/// Configures the Relic application routing and middleware. +final _app = RelicApp() + ..use('/', _requiredHeadersMiddleware) + ..get('/json', respondWith((request) => _responseJson())) + ..get('/plaintext', respondWith((request) => _responsePlainText())) + ..fallback = respondWith((request) => Response.notFound()); + +/// Middleware to inject TFB-required [Server] and [Date] headers globally. +final _requiredHeadersMiddleware = createMiddleware( + onResponse: (response) => response.copyWith( + headers: response.headers.transform( + (headers) => headers + ..server = 'relic' + ..date = DateTime.now(), + ), + ), +); + +/// Handles the '/json' endpoint, returning a pre-encoded JSON response. +Response _responseJson() => Response.ok( + body: Body.fromData( + _jsonEncoder.convert(const {'message': 'Hello, World!'}) as Uint8List, + mimeType: MimeType.json, + ), +); + +/// Handles the '/plaintext' endpoint, returning a simple text response. +Response _responsePlainText() => Response.ok( + body: Body.fromString('Hello, World!', mimeType: MimeType.plainText), +); diff --git a/frameworks/Dart/relic/relic_native/bin/server.dart b/frameworks/Dart/relic/relic_native/bin/server.dart new file mode 100644 index 00000000000..7f158f8e967 --- /dev/null +++ b/frameworks/Dart/relic/relic_native/bin/server.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:relic/relic.dart'; + +/// The fixed TCP port used by the server. +const _defaultPort = 8080; + +/// Reusable UTF-8 JSON encoder for efficient byte array transformations. +final _jsonEncoder = JsonUtf8Encoder(); + +/// Entry point: starts the server utilizing all available CPU cores. +void main() async { + await _app.serve( + address: InternetAddress.anyIPv4, + port: _defaultPort, + noOfIsolates: Platform.numberOfProcessors, + shared: true, // Allows isolates to share the same port. + ); +} + +/// Configures the Relic application routing and middleware. +final _app = RelicApp() + ..use('/', _requiredHeadersMiddleware) + ..get('/json', respondWith((request) => _responseJson())) + ..get('/plaintext', respondWith((request) => _responsePlainText())) + ..fallback = respondWith((request) => Response.notFound()); + +/// Middleware to inject TFB-required [Server] and [Date] headers globally. +final _requiredHeadersMiddleware = createMiddleware( + onResponse: (response) => response.copyWith( + headers: response.headers.transform( + (headers) => headers + ..server = 'relic' + ..date = DateTime.now(), + ), + ), +); + +/// Handles the '/json' endpoint, returning a pre-encoded JSON response. +Response _responseJson() => Response.ok( + body: Body.fromData( + _jsonEncoder.convert(const {'message': 'Hello, World!'}) as Uint8List, + mimeType: MimeType.json, + ), +); + +/// Handles the '/plaintext' endpoint, returning a simple text response. +Response _responsePlainText() => Response.ok( + body: Body.fromString('Hello, World!', mimeType: MimeType.plainText), +); diff --git a/frameworks/Dart/shelf/analysis_options.yaml b/frameworks/Dart/shelf/analysis_options.yaml new file mode 100644 index 00000000000..926fdf8d193 --- /dev/null +++ b/frameworks/Dart/shelf/analysis_options.yaml @@ -0,0 +1,3 @@ +include: package:lints/recommended.yaml +formatter: + trailing_commas: preserve diff --git a/frameworks/Dart/shelf/benchmark_config.json b/frameworks/Dart/shelf/benchmark_config.json index 29200587d0c..5be453b0618 100644 --- a/frameworks/Dart/shelf/benchmark_config.json +++ b/frameworks/Dart/shelf/benchmark_config.json @@ -20,6 +20,25 @@ "display_name": "shelf", "notes": "", "versus": "None" + }, + "aot": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "shelf", + "language": "Dart", + "flavor": "None", + "orm": "None", + "platform": "shelf", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "shelf_aot", + "notes": "", + "versus": "None" } } ] diff --git a/frameworks/Dart/shelf/bin/server.dart b/frameworks/Dart/shelf/bin/server.dart deleted file mode 100755 index e3c3b71ca64..00000000000 --- a/frameworks/Dart/shelf/bin/server.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:isolate'; - -import 'package:shelf/shelf.dart'; -import 'package:shelf/shelf_io.dart' as shelf_io; - -void main(List args) async { - /// Create an [Isolate] containing an [HttpServer] - /// for each processor after the first - for (var i = 1; i < Platform.numberOfProcessors; i++) { - await Isolate.spawn(_startServer, args); - } - - /// Create a [HttpServer] for the first processor - await _startServer(args); -} - -/// Create a request handler -Response _handler(Request request) { - switch (request.url.path) { - case 'json': - return _jsonTest(); - case 'plaintext': - return _plaintextTest(); - default: - return _sendResponse(HttpStatus.notFound); - } -} - -/// Creates and setup a [HttpServer]. -Future _startServer(List _) async { - final server = await shelf_io.serve( - _handler, - InternetAddress.anyIPv4, - 8080, - shared: true, - ); - - /// Sets [HttpServer]'s [serverHeader]. - server - ..defaultResponseHeaders.clear() - ..serverHeader = 'shelf'; -} - -/// Completes the given [request] by writing the [bytes] with the given -/// [statusCode] and [type]. -Response _sendResponse( - int statusCode, { - ContentType? type, - List bytes = const [], -}) { - return Response( - statusCode, - headers: { - HttpHeaders.contentLengthHeader: '${bytes.length}', - HttpHeaders.dateHeader: '${HttpDate.format(DateTime.now())}', - if (type != null) HttpHeaders.contentTypeHeader: type.mimeType, - }, - body: bytes, - ); -} - -/// Completes the given [request] by writing the [response] as JSON. -Response _sendJson(Object response) => _sendResponse( - HttpStatus.ok, - type: ContentType.json, - bytes: _jsonEncoder.convert(response), -); - -/// Completes the given [request] by writing the [response] as plain text. -Response _sendText(String response) => _sendResponse( - HttpStatus.ok, - type: ContentType.text, - bytes: utf8.encode(response), -); - -/// Responds with the JSON test to the [request]. -Response _jsonTest() => _sendJson(const {'message': 'Hello, World!'}); - -/// Responds with the plaintext test to the [request]. -Response _plaintextTest() => _sendText('Hello, World!'); - -final _jsonEncoder = JsonUtf8Encoder(); diff --git a/frameworks/Dart/shelf/pubspec.yaml b/frameworks/Dart/shelf/pubspec.yaml index c41cff1b872..392b9447fe4 100644 --- a/frameworks/Dart/shelf/pubspec.yaml +++ b/frameworks/Dart/shelf/pubspec.yaml @@ -1,7 +1,10 @@ name: shelfbenchmark description: A benchmark of pkg:shelf environment: - sdk: ^3.8.0 + sdk: ^3.11.0 dependencies: - shelf: ^1.0.0 + shelf: ^1.4.2 + +dev_dependencies: + lints: ^6.1.0 diff --git a/frameworks/Dart/shelf/shelf-aot.dockerfile b/frameworks/Dart/shelf/shelf-aot.dockerfile new file mode 100644 index 00000000000..41e8c3b8e0c --- /dev/null +++ b/frameworks/Dart/shelf/shelf-aot.dockerfile @@ -0,0 +1,22 @@ + +FROM dart:3.11.0 AS build +WORKDIR /app + +ARG MAX_ISOLATES=8 + +COPY pubspec.yaml . +COPY shelf_aot/bin/ bin/ + +RUN dart compile aot-snapshot bin/server.dart \ + --define=MAX_ISOLATES=${MAX_ISOLATES} \ + -o server.aot + +FROM gcr.io/distroless/base-debian13 +WORKDIR /app + +COPY --from=build /usr/lib/dart/bin/dartaotruntime /usr/lib/dart/bin/dartaotruntime +COPY --from=build /app/server.aot /app/server.aot + +EXPOSE 8080 + +ENTRYPOINT ["/usr/lib/dart/bin/dartaotruntime", "/app/server.aot"] \ No newline at end of file diff --git a/frameworks/Dart/shelf/shelf.dockerfile b/frameworks/Dart/shelf/shelf.dockerfile index 812b7e959ee..168e1537b22 100644 --- a/frameworks/Dart/shelf/shelf.dockerfile +++ b/frameworks/Dart/shelf/shelf.dockerfile @@ -1,14 +1,15 @@ -FROM dart:3.8 AS builder - -COPY . /app +FROM dart:3.11.0 AS build WORKDIR /app -RUN mkdir build -RUN dart compile exe ./bin/server.dart -o build/server + +COPY pubspec.yaml . +COPY shelf_native/bin/ bin/ + +RUN dart compile exe bin/server.dart -o server FROM scratch -COPY --from=builder /runtime/ / -COPY --from=builder /app/build /bin +COPY --from=build /runtime/ / +COPY --from=build /app/server /bin/server EXPOSE 8080 -CMD ["server"] +ENTRYPOINT ["server"] \ No newline at end of file diff --git a/frameworks/Dart/shelf/shelf_aot/bin/server.dart b/frameworks/Dart/shelf/shelf_aot/bin/server.dart new file mode 100755 index 00000000000..9370835760e --- /dev/null +++ b/frameworks/Dart/shelf/shelf_aot/bin/server.dart @@ -0,0 +1,143 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:math' show min; + +import 'package:shelf/shelf.dart'; +import 'package:shelf/shelf_io.dart' as shelf_io; + +/// Environment declarations are evaluated at compile-time. Use 'const' to +/// ensure values are baked into AOT/Native binaries for the benchmark. +/// +/// From https://api.dart.dev/dart-core/int/int.fromEnvironment.html: +/// "This constructor is only guaranteed to work when invoked as const. +/// It may work as a non-constant invocation on some platforms +/// which have access to compiler options at run-time, +/// but most ahead-of-time compiled platforms will not have this information." +const _maxIsolatesfromEnvironment = int.fromEnvironment('MAX_ISOLATES'); + +/// The fixed TCP port used by the server. +/// Defined here for visibility and ease of configuration. +const _defaultPort = 8080; + +/// A reusable instance of the UTF-8 JSON encoder to efficiently +/// transform Dart objects into byte arrays for HTTP responses. +final _jsonEncoder = JsonUtf8Encoder(); + +/// Internal token used to notify newly spawned processes that they +/// belong to a secondary "worker group". +const _workerGroupTag = '--WORKER-GROUP'; + +void main(List arguments) async { + /// Create a mutable copy of the fixed-length arguments list. + final args = [...arguments]; + + /// Defines local isolate quota, using MAX_ISOLATES if provided. + /// Falls back to total available cores while respecting hardware limits. + var maxIsolates = _maxIsolatesfromEnvironment > 0 + ? min(_maxIsolatesfromEnvironment, Platform.numberOfProcessors) + : Platform.numberOfProcessors; + + /// Determine if this process instance was initialized as a worker group. + if (args.contains(_workerGroupTag)) { + /// Sanitize the argument list to ensure the internal token does not + /// interfere with application-level argument parsing. + args.remove(_workerGroupTag); + } + /// Prevents recursive spawning + /// by ensuring only the primary process can spawn worker groups + else { + /// Calculate the number of secondary worker groups required + /// to fully utilize the available hardware capacity. + /// + /// Each group serves as a container for multiple isolates, + /// helping to bypass internal VM scaling bottlenecks. + final workerGroups = Platform.numberOfProcessors ~/ maxIsolates - 1; + + /// Bootstraps independent worker processes via AOT snapshots. + /// Each process initializes its own Isolate Group. + for (var i = 0; i < workerGroups; i++) { + /// [Platform.script] identifies the AOT snapshot or executable. + /// [Isolate.spawnUri] spawns a new process group via [main()]. + await Isolate.spawnUri(Platform.script, [...args, _workerGroupTag], null); + } + + /// Updates local isolate limits, assigning the primary group + /// the remaining cores after worker group allocation. + maxIsolates = Platform.numberOfProcessors - workerGroups * maxIsolates; + } + + /// Create an [Isolate] containing an [HttpServer] + /// for each processor after the first + for (var i = 1; i < maxIsolates; i++) { + await Isolate.spawn(_startServer, args); + } + + /// Create a [HttpServer] for the first processor + await _startServer(args); +} + +/// Create a request handler +Response _handler(Request request) { + switch (request.url.path) { + case 'json': + return _jsonTest(); + case 'plaintext': + return _plaintextTest(); + default: + return _sendResponse(HttpStatus.notFound); + } +} + +/// Creates and setup a [HttpServer]. +Future _startServer(List _) async { + final server = await shelf_io.serve( + _handler, + InternetAddress.anyIPv4, + _defaultPort, + shared: true, + ); + + /// Sets [HttpServer]'s [serverHeader]. + server + ..defaultResponseHeaders.clear() + ..serverHeader = 'shelf'; +} + +/// Completes the given [request] by writing the [bytes] with the given +/// [statusCode] and [type]. +Response _sendResponse( + int statusCode, { + ContentType? type, + List bytes = const [], +}) { + return Response( + statusCode, + headers: { + HttpHeaders.contentLengthHeader: '${bytes.length}', + HttpHeaders.dateHeader: HttpDate.format(DateTime.now()), + if (type != null) HttpHeaders.contentTypeHeader: type.mimeType, + }, + body: bytes, + ); +} + +/// Completes the given [request] by writing the [response] as JSON. +Response _sendJson(Object response) => _sendResponse( + HttpStatus.ok, + type: ContentType.json, + bytes: _jsonEncoder.convert(response), +); + +/// Completes the given [request] by writing the [response] as plain text. +Response _sendText(String response) => _sendResponse( + HttpStatus.ok, + type: ContentType.text, + bytes: utf8.encode(response), +); + +/// Responds with the JSON test to the [request]. +Response _jsonTest() => _sendJson(const {'message': 'Hello, World!'}); + +/// Responds with the plaintext test to the [request]. +Response _plaintextTest() => _sendText('Hello, World!'); diff --git a/frameworks/Dart/shelf/shelf_native/bin/server.dart b/frameworks/Dart/shelf/shelf_native/bin/server.dart new file mode 100755 index 00000000000..dc8e42ea637 --- /dev/null +++ b/frameworks/Dart/shelf/shelf_native/bin/server.dart @@ -0,0 +1,84 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; + +import 'package:shelf/shelf.dart'; +import 'package:shelf/shelf_io.dart' as shelf_io; + +void main(List args) async { + /// Create an [Isolate] containing an [HttpServer] + /// for each processor after the first + for (var i = 1; i < Platform.numberOfProcessors; i++) { + await Isolate.spawn(_startServer, args); + } + + /// Create a [HttpServer] for the first processor + await _startServer(args); +} + +/// Create a request handler +Response _handler(Request request) { + switch (request.url.path) { + case 'json': + return _jsonTest(); + case 'plaintext': + return _plaintextTest(); + default: + return _sendResponse(HttpStatus.notFound); + } +} + +/// Creates and setup a [HttpServer]. +Future _startServer(List _) async { + final server = await shelf_io.serve( + _handler, + InternetAddress.anyIPv4, + 8080, + shared: true, + ); + + /// Sets [HttpServer]'s [serverHeader]. + server + ..defaultResponseHeaders.clear() + ..serverHeader = 'shelf'; +} + +/// Completes the given [request] by writing the [bytes] with the given +/// [statusCode] and [type]. +Response _sendResponse( + int statusCode, { + ContentType? type, + List bytes = const [], +}) { + return Response( + statusCode, + headers: { + HttpHeaders.contentLengthHeader: '${bytes.length}', + HttpHeaders.dateHeader: HttpDate.format(DateTime.now()), + if (type != null) HttpHeaders.contentTypeHeader: type.mimeType, + }, + body: bytes, + ); +} + +/// Completes the given [request] by writing the [response] as JSON. +Response _sendJson(Object response) => _sendResponse( + HttpStatus.ok, + type: ContentType.json, + bytes: _jsonEncoder.convert(response), +); + +/// Completes the given [request] by writing the [response] as plain text. +Response _sendText(String response) => _sendResponse( + HttpStatus.ok, + type: ContentType.text, + bytes: utf8.encode(response), +); + +/// Responds with the JSON test to the [request]. +Response _jsonTest() => _sendJson(const {'message': 'Hello, World!'}); + +/// Responds with the plaintext test to the [request]. +Response _plaintextTest() => _sendText('Hello, World!'); + +final _jsonEncoder = JsonUtf8Encoder(); diff --git a/frameworks/Dart/start/README.md b/frameworks/Dart/start/README.md deleted file mode 100644 index 0ff26d2b79b..00000000000 --- a/frameworks/Dart/start/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Dart Start Framework Benchmarking Test - -## Note: -The PostgreSQL tests are no longer working. The implementation is still in the framework folder but has been removed from the `benchmark_config.json` file. - -This test adds [Start](https://github.com/lvivski/start), a Sinatra inspired web development framework for Dart, to the [benchmarking test suite](../). The test is based on the Dart Benchmarking Test. - -## Versions - -* [Dart SDK version >=1.3.0](https://launchpad.net/~hachre/+archive/dart) -* [Dart args version 0.11.0+1](https://pub.dev/packages/args) -* [Dart crypto version 0.9.0](https://pub.dev/packages/crypto) -* [Dart mustache version 0.1.8](https://pub.dev/packages/mustache) -* [Dart mongo_dart version 0.1.39](https://pub.dev/packages/mongo_dart) -* [Dart postgresql version 0.2.13](https://pub.dev/packages/postgresql) -* [Dart start version 0.2.4](https://pub.dev/packages/start) -* [Dart yaml version 0.9.0](https://pub.dev/packages/yaml) - -## Test URLs - -### Common - -#### JSON Encoding Test -http://localhost:8080/json - -#### Plaintext Test -http://localhost:8080/plaintext - - -### PostgreSQL - -#### Data-Store/Database Mapping Test -http://localhost:8080/db - -#### Variable Query Test -http://localhost:8080/queries?queries=2 - -#### Fortunes Test -http://localhost:8080/fortunes - -#### Data-Store/Database Update Test -http://localhost:8080/updates - -#### Variable Update Test -http://localhost:8080/updates?queries=2 - - -### MongoDB - -#### Data-Store/Database Mapping Test -http://localhost:8080/db-mongo - -#### Variable Query Test -http://localhost:8080/queries-mongo?queries=2 - -#### Fortunes Test -http://localhost:8080/fortunes-mongo - -#### Data-Store/Database Update Test -http://localhost:8080/updates-mongo - -#### Variable Update Test -http://localhost:8080/updates-mongo?queries=2 - - diff --git a/frameworks/Dart/start/benchmark_config.json b/frameworks/Dart/start/benchmark_config.json deleted file mode 100644 index e7ebf43c308..00000000000 --- a/frameworks/Dart/start/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "start", - "tests": [{ - "default": { - "db_url": "/db-mongo", - "query_url": "/queries-mongo?queries=", - "fortune_url": "/fortunes-mongo", - "update_url": "/updates-mongo?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MongoDB", - "framework": "start", - "language": "Dart", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "start", - "notes": "", - "versus": "dart", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Dart/start/config.toml b/frameworks/Dart/start/config.toml deleted file mode 100644 index a1c46a10578..00000000000 --- a/frameworks/Dart/start/config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[framework] -name = "start" - -[main] -urls.db = "/db-mongo" -urls.query = "/queries-mongo?queries=" -urls.update = "/updates-mongo?queries=" -urls.fortune = "/fortunes-mongo" -approach = "Realistic" -classification = "Micro" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "nginx" -versus = "dart" diff --git a/frameworks/Dart/start/fortunes.mustache b/frameworks/Dart/start/fortunes.mustache deleted file mode 100644 index 77ea1a96cf5..00000000000 --- a/frameworks/Dart/start/fortunes.mustache +++ /dev/null @@ -1,20 +0,0 @@ - - - - Fortunes - - - - - - - - {{#fortunes}} - - - - - {{/fortunes}} -
idmessage
{{id}}{{message}}
- - diff --git a/frameworks/Dart/start/mongodb.yaml b/frameworks/Dart/start/mongodb.yaml deleted file mode 100644 index 3fc0ff375d7..00000000000 --- a/frameworks/Dart/start/mongodb.yaml +++ /dev/null @@ -1,2 +0,0 @@ -host: tfb-database -database: hello_world diff --git a/frameworks/Dart/start/nginx-conf.sh b/frameworks/Dart/start/nginx-conf.sh deleted file mode 100644 index 03444b92454..00000000000 --- a/frameworks/Dart/start/nginx-conf.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# -# create nginx configuration -# -CPU_COUNT=$(nproc) -conf+="user root;\n" -conf+="worker_processes ${CPU_COUNT};\n" -conf+="error_log stderr;\n" -conf+="events {\n" -conf+="\tworker_connections 1024;\n" -conf+="}\n" -conf+="http {\n" -conf+="\taccess_log off;\n" -conf+="\tinclude /etc/nginx/mime.types;\n" -conf+="\tdefault_type application/octet-stream;\n" -conf+="\tsendfile on;\n" -conf+="\tupstream dart_cluster {\n" -current=9001 -end=$(($current+$CPU_COUNT)) -while [ $current -lt $end ]; do - conf+="\t\tserver 127.0.0.1:${current};\n" - let current=current+1 -done -conf+="\t\tkeepalive ${CPU_COUNT};\n" -conf+="\t}\n" -conf+="\tserver {\n" -conf+="\t\tlisten 8080;\n" -conf+="\t\tlocation / {\n" -conf+="\t\t\tproxy_pass http://dart_cluster;\n" -conf+="\t\t\tproxy_http_version 1.1;\n" -conf+="\t\t\tproxy_set_header Connection \"\";\n" -conf+="\t\t}\n" -conf+="\t}\n" -conf+="}" -# -# write nginx configuration to disk -# -echo -e $conf > nginx.conf diff --git a/frameworks/Dart/start/postgresql.yaml b/frameworks/Dart/start/postgresql.yaml deleted file mode 100644 index b57e64ef9be..00000000000 --- a/frameworks/Dart/start/postgresql.yaml +++ /dev/null @@ -1,5 +0,0 @@ -host: tfb-database -port: 5432 -user: benchmarkdbuser -password: benchmarkdbpass -database: hello_world diff --git a/frameworks/Dart/start/pubspec.yaml b/frameworks/Dart/start/pubspec.yaml deleted file mode 100644 index 312f9991141..00000000000 --- a/frameworks/Dart/start/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: DartStartBenchmark -description: A benchmark of Dart Start, a Sinatra inspired web framework -environment: - sdk: ">=1.3.0 <2.0.0" -dependencies: - args: 0.11.0+1 - crypto: 0.9.0 - mongo_dart: 0.1.39 - mustache: 0.1.8 - postgresql: 0.2.13 - start: 0.2.4 - yaml: 0.9.0 \ No newline at end of file diff --git a/frameworks/Dart/start/server.dart b/frameworks/Dart/start/server.dart deleted file mode 100644 index ed2cb504b91..00000000000 --- a/frameworks/Dart/start/server.dart +++ /dev/null @@ -1,359 +0,0 @@ -import "dart:core"; -import "dart:io"; -import 'dart:async' show Future; -import 'dart:convert'; -import 'dart:math' show Random; -import "package:start/start.dart"; -import "package:args/args.dart"; -import 'package:postgresql/postgresql.dart' as pg; -import 'package:postgresql/postgresql_pool.dart' as pgpool; -import 'package:yaml/yaml.dart' as yaml; -import 'package:mustache/mustache.dart' as mustache; -import 'package:mongo_dart/mongo_dart.dart'; -import 'package:crypto/crypto.dart'; - -// Postgres connection pool -var _connectionPool; - -// Fortunes mustache template -var _fortunesTemplate; - -// MongoDB connection -var _mongoDb; - -// World Collection -var _worldCollection; -// Fortunes Collection -var _fortuneCollection; - -// World table size -const _WORLD_TABLE_SIZE = 10000; -// Fortune table size used only for generation of data -const _FORTUNE_TABLE_SIZE = 100; - -final _RANDOM = new Random(); - -class Fortune implements Comparable { - int id; - String message; - - Fortune(this.id, this.message); - - compareTo(Fortune other) => message.compareTo(other.message); -} - - -class World { - int id; - - int randomnumber; - - World(this.id, this.randomnumber); - - toJson() => { "id": id, "randomNumber": randomnumber }; -} - -main(List args) { - var parser = new ArgParser(); - parser.addOption('address', abbr: 'a', defaultsTo: '0.0.0.0'); - parser.addOption('port', abbr: 'p', defaultsTo: '8080'); - parser.addOption('dbconnections', abbr: 'd', defaultsTo: '256'); - - var arguments = parser.parse(args); - - Future.wait([ - new File("postgresql.yaml").readAsString().then((config){ - _connectionPool = new pgpool.Pool( - new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(), - min: int.parse(arguments["dbconnections"]), - max: int.parse(arguments["dbconnections"]) - ); - return _connectionPool.start(); - }), - new File("mongodb.yaml").readAsString().then((config) { - var mongoConfig = yaml.loadYaml(config); - _mongoDb = new Db("mongodb://${mongoConfig["host"]}/${mongoConfig["database"]}"); - return _mongoDb.open().then((_) { - _worldCollection = _mongoDb.collection("world"); - _fortuneCollection = _mongoDb.collection("fortune"); - }); - }), - new File('fortunes.mustache').readAsString().then((template) { - _fortunesTemplate = mustache.parse(template); - }) - ]).then((_) { - start(host: arguments["address"], port: int.parse(arguments["port"])) - .then((Server app) { - - // JSON test - app.get('/json').listen((request) { - - var helloWorld = { - "message": "Hello, World!" - }; - - _setJsonHeaders(request.response); - request.response.send(JSON.encode(helloWorld)); - }); - - - // Query test - app.get("/db").listen((request) { - - _setJsonHeaders(request.response); - - _query().then((data) { - request.response.send(JSON.encode(data)); - }); - }); - - // Queries test - app.get("/queries").listen((request) { - - var queries = _parseQueriesParam(request.param("queries")); - - _setJsonHeaders(request.response); - - Future.wait( - new List.generate( - queries, - (_) => _query(), - growable: false - ) - ) - .then((response) => request.response.send(JSON.encode(response))); - }); - - // Fortunes test - app.get("/fortunes").listen((request) { - _setHtmlHeaders(request.response); - - _connectionPool.connect().then((connection) { - return connection.query('SELECT id, message FROM fortune;') - .map((row) => new Fortune(row[0], row[1])) - .toList() - .whenComplete(() { connection.close(); }); - }).then((fortunes) { - fortunes.add(new Fortune(0, 'Additional fortune added at request time.')); - fortunes.sort(); - request.response.send(_fortunesTemplate.renderString({ - "fortunes": fortunes.map((fortune) => { - "id": fortune.id, - "message": fortune.message - }).toList() - })); - }); - }); - - // Updates test - app.get("/updates").listen((request) { - - var queries = _parseQueriesParam(request.param("queries")); - - _setJsonHeaders(request.response); - - Future.wait(new List.generate(queries, (_) { - return _query() - .then((world) { - world.randomnumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1; - return _connectionPool.connect() - .then((connection) { - return connection.execute( - 'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;', - { - 'randomnumber': world.randomnumber, - 'id': world.id - } - ) - .whenComplete(() { connection.close(); }); - }) - .then((_) => world); - }); - }, growable: false)) - .then((worlds) => request.response.send(JSON.encode(worlds))); - }); - - // Plain text test - app.get("/plaintext").listen((request) { - _setPlainHeaders(request.response); - request.response.send("Hello, World!"); - }); - - // Mongo World dev data generation - app.get("/generate-world").listen((request) { - - _worldCollection.drop() - .then((_) { - var collectionData = new List.generate(_WORLD_TABLE_SIZE, (index) { - return { - "_id": index + 1, - "randomNumber": _RANDOM.nextInt(_WORLD_TABLE_SIZE) - }; - }); - return _worldCollection.insertAll(collectionData); - }) - .then((_) { - request.response.send("Generated"); - }); - }); - - // Mongo Fortune dev data generation - app.get("/generate-fortune").listen((request) { - _fortuneCollection.drop() - .then((_) { - var collectionData = new List.generate(_FORTUNE_TABLE_SIZE, (index) { - var hash = new MD5(); - hash.add(_RANDOM.nextInt(_FORTUNE_TABLE_SIZE).toString().codeUnits); - return { - "_id": index + 1, - "message": CryptoUtils.bytesToHex(hash.close()) - }; - }); - return _fortuneCollection.insertAll(collectionData); - }) - .then((_) { - request.response.send("Generated"); - }); - - }); - - // Mongo query test - app.get("/db-mongo").listen((request) { - - _setJsonHeaders(request.response); - - _mongoQuery().then((data) { - request.response.json({ - "id": data["_id"], - "randomNumber": data["randomNumber"] - }); - }); - }); - - // Mongo queries test - app.get("/queries-mongo").listen((request) { - - var queries = _parseQueriesParam(request.param("queries")); - - _setJsonHeaders(request.response); - - Future.wait( - new List.generate( - queries, - (_) => _mongoQuery(), - growable: false - ) - ) - .then((response) { - var results = response.map((world) { - return { - "id": world["_id"], - "randomNumber": world["randomNumber"] - }; - }); - request.response.send(JSON.encode(results.toList())); - }); - }); - - // Mongo updates test - app.get("/updates-mongo").listen((request) { - var queries = _parseQueriesParam(request.param("queries")); - - _setJsonHeaders(request.response); - - Future.wait(new List.generate(queries, (index) { - return _mongoQuery() - .then((world) { - world["randomNumber"] = _RANDOM.nextInt(_WORLD_TABLE_SIZE); - return _worldCollection.update( { "_id": world["_id"] }, world) - .then((_) => world); - }); - }, growable: false)) - .then((worlds) { - var result = worlds.map((world) { - return { - "id": world["_id"], - "randomNumber": world["randomNumber"] - }; - }); - request.response.send(JSON.encode(result.toList())); - }); - }); - - - // Mongo fortunes test - app.get("/fortunes-mongo").listen((request) { - - _setHtmlHeaders(request.response); - - _fortuneCollection.find().toList().then((fortunes) { - fortunes = fortunes.map((fortune) { - return new Fortune(fortune["_id"].toInt(), fortune["message"]); - }).toList(); - fortunes.add(new Fortune(0, 'Additional fortune added at request time.')); - fortunes.sort(); - request.response.send(_fortunesTemplate.renderString({ - "fortunes": fortunes.map((fortune) => { - "id": fortune.id, - "message": fortune.message - }).toList() - })); - }); - }); - - }); - }); -} - -// set JSON headers -_setJsonHeaders(response) { - _setHeaders(response); - response - .header(HttpHeaders.CONTENT_TYPE, 'application/json; charset=UTF-8'); -} - -// set plain text headers -_setPlainHeaders(response) { - _setHeaders(response); - response - .header(HttpHeaders.CONTENT_TYPE, 'text/plain; charset=UTF-8'); -} - -// set HTML headers -_setHtmlHeaders(response) { - _setHeaders(response); - response - .header(HttpHeaders.CONTENT_TYPE, 'text/html; charset=UTF-8'); -} - -// set common headers -_setHeaders(response) { - // disable gzip encoding - response.header(HttpHeaders.CONTENT_ENCODING, "") - ..header(HttpHeaders.DATE, new DateTime.now()); -} - -// parse queries param -_parseQueriesParam(param) { - return param.isEmpty ? 1 : int.parse(param, radix: 10, onError: (_) => 1).clamp(1, 500); -} - -// runs a query and returns a promise -_query() { - return _connectionPool.connect().then((connection) { - return connection - .query('SELECT id, randomnumber FROM world WHERE id = @id;', { 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 }) - .single - .then((row) =>new World(row[0], row[1])) - .whenComplete(() { - connection.close(); - }); - }); -} - -// runs a mongo query and returns a promise -_mongoQuery() { - return _worldCollection.findOne({ - "_id": _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 - }); -} diff --git a/frameworks/Dart/start/start-servers.sh b/frameworks/Dart/start/start-servers.sh deleted file mode 100644 index 4795cc872be..00000000000 --- a/frameworks/Dart/start/start-servers.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# -# start dart servers -# -CPU_COUNT=$(nproc) -current=9001 -end=$(($current+$CPU_COUNT)) -while [ $current -lt $end ]; do - dart server.dart -a 127.0.0.1 -p $current -d ${CPU_COUNT} & - let current=current+1 -done diff --git a/frameworks/Dart/start/start.dockerfile b/frameworks/Dart/start/start.dockerfile deleted file mode 100644 index 133b058d388..00000000000 --- a/frameworks/Dart/start/start.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM google/dart:1.24 - -RUN apt-get update -yqq && apt-get install -yqq nginx - -ADD ./ /start -WORKDIR /start - -RUN pub upgrade - -RUN chmod -R 777 /start - -EXPOSE 8080 - -CMD ./nginx-conf.sh && \ - ./start-servers.sh && \ - sleep 20 && nginx -c /start/nginx.conf -g "daemon off;" diff --git a/frameworks/Dart/stream/README.md b/frameworks/Dart/stream/README.md deleted file mode 100644 index 07aafcd28df..00000000000 --- a/frameworks/Dart/stream/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Dart Start Framework Benchmarking Test - -## Note: -The PostgreSQL tests are no longer working. The implementation is still in the framework folder but has been removed from the `benchmark_config.json` file. - -This test adds [Stream](https://github.com/rikulo/stream), a lightweight Dart web server, to the [benchmarking test suite](../). The test is based on the Dart Benchmarking Test. - -## Versions - -* [Dart SDK version >=1.3](https://launchpad.net/~hachre/+archive/dart) -* [Dart args version 0.11.0+1](https://pub.dev/packages/args) -* [Dart crypto version 0.9.0](https://pub.dev/packages/crypto) -* [Dart mongo_dart version 0.1.39](https://pub.dev/packages/mongo_dart) -* [Dart postgresql version 0.2.13](https://pub.dev/packages/postgresql) -* [Dart stream version 1.2.0](https://pub.dev/packages/start) -* [Dart yaml version 0.9.0](https://pub.dev/packages/yaml) - -## Test URLs - -### Common - -#### JSON Encoding Test -http://localhost:8080/json - -#### Plaintext Test -http://localhost:8080/plaintext - - -### PostgreSQL - -#### Data-Store/Database Mapping Test -http://localhost:8080/db - -#### Variable Query Test -http://localhost:8080/queries?queries=2 - -#### Fortunes Test -http://localhost:8080/fortunes - -#### Data-Store/Database Update Test -http://localhost:8080/updates - -#### Variable Update Test -http://localhost:8080/updates?queries=2 - - -### MongoDB - -#### Data-Store/Database Mapping Test -http://localhost:8080/db-mongo - -#### Variable Query Test -http://localhost:8080/queries-mongo?queries=2 - -#### Fortunes Test -http://localhost:8080/fortunes-mongo - -#### Data-Store/Database Update Test -http://localhost:8080/updates-mongo - -#### Variable Update Test -http://localhost:8080/updates-mongo?queries=2 - diff --git a/frameworks/Dart/stream/benchmark_config.json b/frameworks/Dart/stream/benchmark_config.json deleted file mode 100644 index e6698b7ce64..00000000000 --- a/frameworks/Dart/stream/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "stream", - "tests": [{ - "default": { - "db_url": "/db-mongo", - "query_url": "/queries-mongo?queries=", - "fortune_url": "/fortunes-mongo", - "update_url": "/updates-mongo?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MongoDB", - "framework": "stream", - "language": "Dart", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "stream", - "notes": "", - "versus": "dart", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Dart/stream/config.toml b/frameworks/Dart/stream/config.toml deleted file mode 100644 index 875c54e8a0f..00000000000 --- a/frameworks/Dart/stream/config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[framework] -name = "stream" - -[main] -urls.db = "/db-mongo" -urls.query = "/queries-mongo?queries=" -urls.update = "/updates-mongo?queries=" -urls.fortune = "/fortunes-mongo" -approach = "Realistic" -classification = "Micro" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "nginx" -versus = "dart" diff --git a/frameworks/Dart/stream/fortunesView.rsp.dart b/frameworks/Dart/stream/fortunesView.rsp.dart deleted file mode 100644 index 9ce2280cae9..00000000000 --- a/frameworks/Dart/stream/fortunesView.rsp.dart +++ /dev/null @@ -1,50 +0,0 @@ -//Auto-generated by RSP Compiler -//Source: fortunesView.rsp.html -part of stream_benchmark; - -/** Template, fortunesView, for rendering the view. */ -Future fortunesView(HttpConnect connect, {List fortunes}) { //#2 - var _t0_, _cs_ = new List(); - HttpRequest request = connect.request; - HttpResponse response = connect.response; -// Rsp.init(connect, "text/html; charset=utf-8"); - - response.write(""" - - - Fortunes - - - - - - - -"""); //#2 - - for (var fortune in fortunes) { //for#13 - - response.write(""" - - - -"""); //#16 - } //for - - response.write("""
idmessage
"""); //#14 - - response.write(Rsp.nnx(fortune.id)); //#15 - - - response.write(""""""); //#15 - - response.write(Rsp.nnx(fortune.message)); //#16 - - - response.write("""
- - -"""); //#19 - - return Rsp.nnf(); -} diff --git a/frameworks/Dart/stream/fortunesView.rsp.html b/frameworks/Dart/stream/fortunesView.rsp.html deleted file mode 100644 index fe8d2333af1..00000000000 --- a/frameworks/Dart/stream/fortunesView.rsp.html +++ /dev/null @@ -1,21 +0,0 @@ -[:page partOf="stream_benchmark" args="List fortunes"] - - - - Fortunes - - - - - - - - [:for fortune in fortunes] - - - - - [/for] -
idmessage
[=fortune.id][=fortune.message]
- - diff --git a/frameworks/Dart/stream/mongodb.yaml b/frameworks/Dart/stream/mongodb.yaml deleted file mode 100644 index 3fc0ff375d7..00000000000 --- a/frameworks/Dart/stream/mongodb.yaml +++ /dev/null @@ -1,2 +0,0 @@ -host: tfb-database -database: hello_world diff --git a/frameworks/Dart/stream/nginx-conf.sh b/frameworks/Dart/stream/nginx-conf.sh deleted file mode 100644 index 03444b92454..00000000000 --- a/frameworks/Dart/stream/nginx-conf.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# -# create nginx configuration -# -CPU_COUNT=$(nproc) -conf+="user root;\n" -conf+="worker_processes ${CPU_COUNT};\n" -conf+="error_log stderr;\n" -conf+="events {\n" -conf+="\tworker_connections 1024;\n" -conf+="}\n" -conf+="http {\n" -conf+="\taccess_log off;\n" -conf+="\tinclude /etc/nginx/mime.types;\n" -conf+="\tdefault_type application/octet-stream;\n" -conf+="\tsendfile on;\n" -conf+="\tupstream dart_cluster {\n" -current=9001 -end=$(($current+$CPU_COUNT)) -while [ $current -lt $end ]; do - conf+="\t\tserver 127.0.0.1:${current};\n" - let current=current+1 -done -conf+="\t\tkeepalive ${CPU_COUNT};\n" -conf+="\t}\n" -conf+="\tserver {\n" -conf+="\t\tlisten 8080;\n" -conf+="\t\tlocation / {\n" -conf+="\t\t\tproxy_pass http://dart_cluster;\n" -conf+="\t\t\tproxy_http_version 1.1;\n" -conf+="\t\t\tproxy_set_header Connection \"\";\n" -conf+="\t\t}\n" -conf+="\t}\n" -conf+="}" -# -# write nginx configuration to disk -# -echo -e $conf > nginx.conf diff --git a/frameworks/Dart/stream/postgresql.yaml b/frameworks/Dart/stream/postgresql.yaml deleted file mode 100644 index b57e64ef9be..00000000000 --- a/frameworks/Dart/stream/postgresql.yaml +++ /dev/null @@ -1,5 +0,0 @@ -host: tfb-database -port: 5432 -user: benchmarkdbuser -password: benchmarkdbpass -database: hello_world diff --git a/frameworks/Dart/stream/pubspec.yaml b/frameworks/Dart/stream/pubspec.yaml deleted file mode 100644 index c26431d10cd..00000000000 --- a/frameworks/Dart/stream/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: DartStreamBenchmark -description: A benchmark for Stream, a lightweight Dart web server -environment: - sdk: ">=1.3.0 <2.0.0" -dependencies: - args: 0.11.0+1 - crypto: 0.9.0 - mongo_dart: 0.1.39 - postgresql: 0.2.13 - rikulo_commons: ">=1.0.0 <2.0.0" - stream: 1.2.0 - yaml: 0.9.0 diff --git a/frameworks/Dart/stream/server.dart b/frameworks/Dart/stream/server.dart deleted file mode 100644 index 9fa774bffbe..00000000000 --- a/frameworks/Dart/stream/server.dart +++ /dev/null @@ -1,308 +0,0 @@ -library stream_benchmark; - -import "dart:core"; -import "dart:io"; -import 'dart:async' show Future; -import 'dart:convert'; -import 'dart:math' show Random; -import "package:stream/stream.dart"; -import "package:args/args.dart"; -import 'package:postgresql/postgresql.dart' as pg; -import 'package:postgresql/postgresql_pool.dart' as pgpool; -import 'package:yaml/yaml.dart' as yaml; -import 'package:mongo_dart/mongo_dart.dart'; - -part "fortunesView.rsp.dart"; - -// URI mapping to request handlers -var _uriMapping = { - "/db": _dbTest, - "/json": _jsonTest, - "/queries": _queriesTest, - "/updates": _updatesTest, - "/fortunes": _fortunesTest, - "/plaintext": _plaintextTest, - "/db-mongo": _dbMongoTest, - "/queries-mongo": _queriesMongoTest, - "/updates-mongo": _updatesMongoTest, - "/fortunes-mongo": _fortunesMongoTest -}; - -// filter map to set the headers for the request -var _filterMapping = { - "/db": _jsonHeadersFilter, - "/json": _jsonHeadersFilter, - "/queries": _jsonHeadersFilter, - "/updates": _jsonHeadersFilter, - "/fortunes": _htmlHeadersFilter, - "/plaintext": _plainHeadersFilter, - "/db-mongo": _jsonHeadersFilter, - "/queries-mongo": _jsonHeadersFilter, - "/updates-mongo": _jsonHeadersFilter, - "/fortunes-mongo": _htmlHeadersFilter -}; - -// Postgres connection pool -var _connectionPool; - -// Fortunes mustache template -var _fortunesTemplate; - -// MongoDB connection -var _mongoDb; - -// World Collection -var _worldCollection; - -// Fortunes Collection -var _fortuneCollection; - -// World table size -const _WORLD_TABLE_SIZE = 10000; -// Fortune table size used only for generation of data -const _FORTUNE_TABLE_SIZE = 100; - -final _RANDOM = new Random(); - -class Fortune implements Comparable { - int id; - - String message; - - Fortune(this.id, this.message); - - compareTo(Fortune other) => message.compareTo(other.message); -} - -class World { - int id; - - int randomnumber; - - World(this.id, this.randomnumber); - - toJson() => { "id": id, "randomNumber": randomnumber }; -} - -main(List args) { - - var parser = new ArgParser(); - parser.addOption('address', abbr: 'a', defaultsTo: '0.0.0.0'); - parser.addOption('port', abbr: 'p', defaultsTo: '8080'); - parser.addOption('dbconnections', abbr: 'd', defaultsTo: '256'); - - var arguments = parser.parse(args); - - Future.wait([ - new File("postgresql.yaml").readAsString().then((config){ - _connectionPool = new pgpool.Pool( - new pg.Settings.fromMap(yaml.loadYaml(config)).toUri(), - min: int.parse(arguments["dbconnections"]), - max: int.parse(arguments["dbconnections"]) - ); - return _connectionPool.start(); - }), - new File("mongodb.yaml").readAsString().then((config) { - var mongoConfig = yaml.loadYaml(config); - _mongoDb = new Db("mongodb://${mongoConfig["host"]}/${mongoConfig["database"]}"); - return _mongoDb.open().then((_) { - _worldCollection = _mongoDb.collection("world"); - _fortuneCollection = _mongoDb.collection("fortune"); - }); - }) - ]).then((_) { - new StreamServer(uriMapping: _uriMapping, filterMapping: _filterMapping).start(address: arguments["address"], port: int.parse(arguments["port"])); - }); -} - -_jsonTest(HttpConnect connect) { - var helloWorld = { - "message": "Hello, World!" - }; - - connect.response.write(JSON.encode(helloWorld)); -} - -_dbTest(HttpConnect connect) { - - return _query().then((data) { - connect.response.write(JSON.encode(data)); - }); -} - -_queriesTest(HttpConnect connect) { - var queries = _parseQueriesParam(connect.request.uri.queryParameters["queries"]); - - return Future.wait( - new List.generate( - queries, - (_) => _query(), - growable: false - ) - ) - .then((response) => connect.response.write(JSON.encode(response))); -} - -_updatesTest(HttpConnect connect) { - var queries = _parseQueriesParam(connect.request.uri.queryParameters["queries"]); - - return Future.wait(new List.generate(queries, (_) { - return _query() - .then((world) { - world.randomnumber = _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1; - return _connectionPool.connect() - .then((connection) { - return connection.execute( - 'UPDATE world SET randomnumber = @randomnumber WHERE id = @id;', - { - 'randomnumber': world.randomnumber, - 'id': world.id - } - ) - .whenComplete(() { connection.close(); }); - }) - .then((_) => world); - }); - }, growable: false)) - .then((worlds) => connect.response.write(JSON.encode(worlds))); -} - -_fortunesTest(HttpConnect connect) { - - return _connectionPool.connect().then((connection) { - return connection.query('SELECT id, message FROM fortune;') - .map((row) => new Fortune(row[0], row[1])) - .toList() - .whenComplete(() { connection.close(); }); - }).then((fortunes) { - fortunes.add(new Fortune(0, 'Additional fortune added at request time.')); - fortunes.sort(); - return fortunesView(connect, fortunes: fortunes); - }); -} - -_plaintextTest(HttpConnect connect) { - - connect.response.write("Hello, World!"); -} - -_dbMongoTest(HttpConnect connect) { - - return _mongoQuery().then((data) { - connect.response.write(JSON.encode({ - "id": data["_id"], - "randomNumber": data["randomNumber"] - })); - }); -} - -_queriesMongoTest(HttpConnect connect) { - var queries = _parseQueriesParam(connect.request.uri.queryParameters["queries"]); - - return Future.wait( - new List.generate( - queries, - (_) => _mongoQuery(), - growable: false - ) - ) - .then((response) { - var results = response.map((world) { - return { - "id": world["_id"], - "randomNumber": world["randomNumber"] - }; - }); - connect.response.write(JSON.encode(results.toList())); - }); -} - -_updatesMongoTest(HttpConnect connect) { - var queries = _parseQueriesParam(connect.request.uri.queryParameters["queries"]); - - return Future.wait(new List.generate(queries, (index) { - return _mongoQuery() - .then((world) { - world["randomNumber"] = _RANDOM.nextInt(_WORLD_TABLE_SIZE); - return _worldCollection.update( { "_id": world["_id"] }, world) - .then((_) => world); - }); - }, growable: false)) - .then((worlds) { - var result = worlds.map((world) { - return { - "id": world["_id"], - "randomNumber": world["randomNumber"] - }; - }); - connect.response.write(JSON.encode(result.toList())); - }); -} - -_fortunesMongoTest(HttpConnect connect) { - - return _fortuneCollection.find().toList().then((fortunes) { - fortunes = fortunes.map((fortune) { - return new Fortune(fortune["_id"].toInt(), fortune["message"]); - }).toList(); - fortunes.add(new Fortune(0, 'Additional fortune added at request time.')); - fortunes.sort(); - return fortunesView(connect, fortunes: fortunes); - }); -} - -// set common headers -_setHeaders(HttpResponse response) { - // disable gzip encoding - response.headers.set(HttpHeaders.CONTENT_ENCODING, ""); - response.headers.set(HttpHeaders.DATE, new DateTime.now()); -} - -// set JSON headers for matching requests -_jsonHeadersFilter(HttpConnect connect, Future chain(HttpConnect conn)) { - _setHeaders(connect.response); - connect.response.headers.set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); - - return chain(connect); -} - -// set plain text headers for matching requests -_plainHeadersFilter(HttpConnect connect, Future chain(HttpConnect conn)) { - _setHeaders(connect.response); - connect.response.headers.set(HttpHeaders.CONTENT_TYPE, "text/plain; charset=UTF-8"); - - return chain(connect); -} - -// set HTML headers for matching requests -_htmlHeadersFilter(HttpConnect connect, Future chain(HttpConnect conn)) { - _setHeaders(connect.response); - connect.response.headers.set(HttpHeaders.CONTENT_TYPE, "text/html; charset=UTF-8"); - - return chain(connect); -} - -// parse queries param -_parseQueriesParam(param) { - return (param == null || param.isEmpty) ? 1 : int.parse(param, radix: 10, onError: (_) => 1).clamp(1, 500); -} - -// runs a query and returns a promise -_query() { - return _connectionPool.connect().then((connection) { - return connection - .query('SELECT id, randomnumber FROM world WHERE id = @id;', { 'id': _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 }) - .single - .then((row) =>new World(row[0], row[1])) - .whenComplete(() { - connection.close(); - }); - }); -} - -// runs a mongo query and returns a promise -_mongoQuery() { - return _worldCollection.findOne({ - "_id": _RANDOM.nextInt(_WORLD_TABLE_SIZE) + 1 - }); -} diff --git a/frameworks/Dart/stream/start-servers.sh b/frameworks/Dart/stream/start-servers.sh deleted file mode 100644 index 4795cc872be..00000000000 --- a/frameworks/Dart/stream/start-servers.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# -# start dart servers -# -CPU_COUNT=$(nproc) -current=9001 -end=$(($current+$CPU_COUNT)) -while [ $current -lt $end ]; do - dart server.dart -a 127.0.0.1 -p $current -d ${CPU_COUNT} & - let current=current+1 -done diff --git a/frameworks/Dart/stream/stream.dockerfile b/frameworks/Dart/stream/stream.dockerfile deleted file mode 100644 index 045241fc2bc..00000000000 --- a/frameworks/Dart/stream/stream.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM google/dart:1.24 - -RUN apt-get update -yqq && apt-get install -yqq nginx - -ADD ./ /stream -WORKDIR /stream - -RUN pub upgrade - -RUN chmod -R 777 /stream - -EXPOSE 8080 - -CMD ./nginx-conf.sh && \ - ./start-servers.sh && \ - sleep 20 && nginx -c /stream/nginx.conf -g "daemon off;" diff --git a/frameworks/Erlang/chicagoboss/benchmark_config.json b/frameworks/Erlang/chicagoboss/benchmark_config.json deleted file mode 100755 index f3481c3245c..00000000000 --- a/frameworks/Erlang/chicagoboss/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "chicagoboss", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "None", - "framework": "ChicagoBoss", - "language": "Erlang", - "flavor": "None", - "orm": "raw", - "platform": "beam", - "webserver": "cowboy", - "os": "Linux", - "database_os": "Linux", - "display_name": "ChicagoBoss", - "notes": "", - "versus": "", - "tags": ["broken"] - }}] -} diff --git a/frameworks/Erlang/chicagoboss/boss.config b/frameworks/Erlang/chicagoboss/boss.config deleted file mode 100755 index 28805d4f3c9..00000000000 --- a/frameworks/Erlang/chicagoboss/boss.config +++ /dev/null @@ -1,409 +0,0 @@ -%% vim: ts=4 sw=4 et ft=erlang -%%% -%%% CHICAGO BOSS PROJECT SKELETON -%%% -%%% This file can be modified by you to avoid you needing to reenter -%%% defaults when creating new projects. For full configuration -%%% details, please visit -%%% https://github.com/ChicagoBoss/ChicagoBoss/wiki/Configuration - -%%% When running tests, you may want to create a separate configuration file -%%% "boss.test.config" which, if present, will be read instead of boss.config. - -[{boss, [ - {path, "./deps/boss"}, - {applications, [chicagoboss]}, - {assume_locale, "en"}, - -%%%%%%%%%%%% -%% System %% -%%%%%%%%%%%% - -%% vm_cookie - Erlang cookie, must be the same for all nodes in the -%% cluster. - -%% vm_name - Node name to use in production. Must be unique for all -%% nodes in the cluster. Defaults to @. -%% vm_sname - Node name to use if you wish to use a "short name" instead of a -%% full name. -%% vm_max_processes - The limit of processes that the VM is allowed to -%% spawn. Defaults to 32768 (the usual system default). - -% {vm_cookie, "secret"}, -% {vm_name, "leader@localhost"} -% {vm_sname, "shortname"}, -% {vm_max_processes, 32768}, - - -%%%%%%%%%%%%%%%%%%%%%%%% -%% Controller Filters %% -%%%%%%%%%%%%%%%%%%%%%%%% - -%% controller_filter_config - Specify defaults for controller filters -%% Sub-key 'lang' can be set to the atom 'auto' to autodetermine language -%% universally, or can be set to a specific language by setting a string (e.g. -%% "en" or "de") - -% {controller_filter_config, [ -% {lang, auto} -% ]}, - -%%%%%%%%%%%%%% -%% Compiler %% -%%%%%%%%%%%%%% - -%% See compile(3) for a full list of options - -% {compiler_options, [return_errors]}, - -%%%%%%%%%%% -%% Cache %% -%%%%%%%%%%% - -%% cache_adapter - Which cache adapter to use. Currently the only -%% valid value is memcached_bin. -%% cache_enable - Whether to enable the cache. Defaults to false. -%% cache_servers - A list of cache servers ({Host, Port, -%% PoolSize}). Defaults to [{"localhost", 11211, 1}]. -%% cache_exp_time- The maximum time to keep a cache entry, in -%% seconds. Defaults to 60. - -% {cache_adapter, memcached_bin}, -% {cache_enable, false}, -% {cache_servers, [{"localhost", 11211, 1}]}, -% {cache_exp_time, 60}, - -%%%%%%%%%%%%%% -%% Database %% -%%%%%%%%%%%%%% - -%% db_host - The hostname of the database. Defaults to "localhost". -%% db_port - The port of the database. Defaults to 1978. -%% db_adapter - The database adapter to use. Valid values are: -%% mock - In-memory (non-persistent) database, useful for testing -%% mnesia - Mnesia -%% mongodb- MongoDB -%% mysql - MySQL -%% pgsql - PostgreSQL -%% riak - Riak -%% tyrant - Tokyo Tyrant -%% db_username - The username used for connecting to the database (if -%% needed). -%% db_password - The password used for connecting to the database (if -%% needed). -%% db_database - The name of the database to connect to (if needed). -%% db_cache_enable - Whether to enable the cache in boss_db. Defaults -%% to false. Requires cache_enable to be set to true. - - {db_host, "tfb-database"}, - {db_port, 1978}, - {db_adapter, mock}, -% {db_username, "boss"}, -% {db_password, "boss"}, -% {db_database, "boss"}, - -%% MongoDB only -%% -%% Read https://github.com/TonyGen/mongodb-erlang#readme for details -%% db_write_mode - defaults to safe -%% db_read_mode - defaults to master -% {db_write_mode, safe}, -% {db_read_mode, master}, - -%% Database sharding -%% A list of proplists with per-shard database configuration. -%% The proplists override the above options, and should contain two -%% additional options: -%% {db_shards, [ -%% [ -%% {db_host, "localhost"}, -%% {db_adapter, mysql}, -%% {db_port, 3306}, -%% {db_username, "dbuser"}, -%% {db_password, "dbpass"}, -%% {db_database, "database"}, -%% {db_shard_id, shard_id_atom}, -%% {db_shard_models, [model_atom_1, model_atom_2, -%% model_atom_3, etc]} -%% ] -%% ]}, - -%%%%%%%%%% -%% Mail %% -%%%%%%%%%% - -%% mail_driver - The email delivery driver to use. Valid values are: -%% boss_mail_driver_smtp - SMTP delivery. If mail_relay is present, -%% it is used as a relay, otherwise direct delivery is attempted. -%% boss_mail_driver_mock - A black hole, useful for testing. -%% mail_relay_host - The relay server for SMTP mail deliveries. -%% mail_relay_username -The username used for connecting to the SMTP -%% relay (if needed). -%% mail_relay_password -The password used for connecting to the SMTP -%% relay (if needed). - -% {mail_driver, boss_mail_driver_mock}, -% {mail_relay_host, "smtp.example.com"}, -% {mail_relay_username, "webmaster@example.com"}, -% {mail_relay_password, "mailpassword"}, - - -%%%%%%%%%%%%%%%%%% -%% Master Node %% -%%%%%%%%%%%%%%%%%% - - -%% master_node - -%% For distributed configurations, the name of the master node. -%% The master node runs global services (incoming mail, message -%% queue, events, sessions). -%% Should be an atom, e.g. somenode@somehost. -%% The node name is specified in the -sname or -name argument in the -%% startup script. - -% {master_node, 'master@example.com'}, - -%%%%%%%%%%%%%%% -%% Webserver %% -%%%%%%%%%%%%%%% - -%% port - The port to run the server on. Defaults to 8001. -%% server - The HTTP server to use. Valid values are: -%% mochiweb - The Mochiweb Web Server -%% cowboy - The Cowboy Web Server (Comet, WebSockets, highly scalable, ...) - {port, 8080}, - {server, cowboy}, - -%%%%%%%%%%%%%% -%% Websocket %% -%%%%%%%%%%%%%% - %% you can specify a global timeout for your websocket connection - %% when a websocket is idle more than the timeout, it is closed by the webserver - %% and you receive in your handle_close function {normal, timeout} as the - %% reason. - - %{websocket_timeout, 5000}, - -%%%%%%%%%%%%%% -%% Sessions %% -%%%%%%%%%%%%%% - -%% session_adapter - Selects the session driver to use. Valid values: -%% cache - Store sessions in the configured cache -%% servers. Requires cache_enable to be set to true. -%% ets (default) -%% mnesia - -%% session_enable - Whether to enable sessions. Defaults to true. -%% session_key - Cookie key for sessions. Defaults to "_boss_session". -%% session_exp_time - Expiration time in seconds for the session -%% cookie. Defaults to 525600, i.e. 6 days, 2 hours. -%% session_mnesia_nodes, for {session_adapter, mnesia} only - List of -%% Mnesia nodes, defaults to node(). -%% session_domain - (optional, sets the Domain=x cookie option), -%% this can be used by ex: to enable subdomain apps -%% (*.domain.com) with the param ".domain.com" => {session_domain, -%% ".domain.com"} - - {session_adapter, mock}, - {session_key, "_boss_session"}, - {session_exp_time, 525600}, - {session_cookie_http_only, false}, - {session_cookie_secure, false}, -% {session_enable, true}, -% {session_mnesia_nodes, [node()]}, % <- replace "node()" with a node name -% {session_domain, ".domain.com"}, - -%%%%%%%%%%%%%%% -%% Templates %% -%%%%%%%%%%%%%%% - -%% template_tag_modules - List of external modules to search for -%% custom ErlyDTL tags. -%% template_filter_modules - List of external modules to search for -%% custom ErlyDTL filters. -%% template_auto_escape - Controls automatic HTML escaping of template -%% values. Enabled by default. - {template_tag_modules, []}, - {template_filter_modules, []}, - {template_auto_escape, true}, - -%%%%%%%%%%%%%%%%%%%%% -%% Incoming Emails %% -%%%%%%%%%%%%%%%%%%%%% - -%% smtp_server_enable - Enable the SMTP server for incoming mail -%% smtp_server_address - The address that the SMTP server should bind -%% to. Defaults to {0, 0, 0, 0} (all interfaces). -%% smtp_server_domain - The host name of the SMTP server -%% smtp_server_port - The port that the SMTP server should listen -%% on. Defaults to 25. - -% {smtp_server_enable, false}, -% {smtp_server_address, {0, 0, 0, 0}}, -% {smtp_server_domain, "smtp.example.com"}, -% {smtp_server_port, 25}, - -%% smtp_server_protocol - The protocol that the SMTP server should -%% use. Valid values are: -%% tcp (default) -%% ssl -% {smtp_server_protocol, tcp}, - -%%%%%%%%% -%% SSL %% -%%%%%%%%% - -%% ssl_enable - Enable HTTP over SSL -%% ssl_options - SSL options; see ssl(3erl) - -% {ssl_enable, true}, -% {ssl_options, []}, - -%%%%%%%%%%%%%%%%%%%% -%% LOG FORMATTING %% -%%%%%%%%%%%%%%%%%%%% - -%% Set log_stack_multiline to true to make stack traces more readable at the -%% cost of spanning multiple lines - -% {log_stack_multiline, true}, - - {dummy, true} % a final dummy option so we don't have to keep track of commas -]}, - -%% MESSAGE QUEUE - -{ tinymq, [ -%% max_age- Maximum age of messages in the [message queue], in -%% seconds. Defaults to 60. - % {max_age, 60} -]}, - -%%%%%%%%%%%%% -%% Logging %% -%%%%%%%%%%%%% - -%% Lager default config. -%% More info: https://github.com/basho/lager - -{lager, [ - {handlers, [ - {lager_console_backend, info}, - {lager_file_backend, [ - {"log/error.log", error, 10485760, "$D0", 5}, - {"log/console.log", info, 10485760, "$D0", 5} - ]} - ]}, - - %% Colored output, if you want to modify the colors, see - %% https://github.com/basho/lager/blob/master/src/lager.app.src - % {colored, true}, - - {dummy, true} - ]}, - -%%%%%%%%%%%%%%% -%% Webserver %% -%%%%%%%%%%%%%%% - -{simple_bridge, [ - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - %% STANDARD SETTINGS - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - {server_name, boss_webserver}, - %% You can call this whatever you want. Name it after your application - %% is probably best - - {handler, boss_simple_bridge_handler}, - %% the name of the simple_bridge handler module, which is expected to - %% export run/1, ws_init/1, ws_message/1, ws_info/1, and terminate/1 - - {backend, cowboy}, - %% cowboy | inets | mochiweb | webmachine | yaws - %% It's not necessary to specify this in the confiugration unless you - %% want to start simple_bridge with application:start(simple_bridge) or - %% simple_bridge:start/0 - - {address, "0.0.0.0"}, - %% IP address to bind, either in tuple format or string - %% use "0.0.0.0" to start on all interfaces available - - {port, 8080}, - %% Port to bind - - {document_root, "./priv/static"}, - %% The path on the local machine to handle static files - - {static_paths, ["js/"]}, - %% The list of paths to be automatically translated to static paths by - %% simple_bridge - - %% {anchor, AnchorModule}, - %% If not provided or set to undefined, will use - %% BACKEND_simple_bridge_anchor. This is the backend-specific module - %% for handling the requests from your chosen backend. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - %% FILE UPLOAD SETTINGS - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - {max_post_size, 100}, - %% No multipart request greater than above will be accepted. Units are - %% MB - - {max_file_size, 100}, - %% No single uploaded file will be accepted greater than the above. - %% Units are MB. - - {max_file_in_memory_size, 0}, - %% If a file is less than the above, then instead of writing the file - %% to disk, it'll be retained in memory and can be retrieved by - %% sb_uploaded_file:data/1. See the README for more info. - - {scratch_dir, "./scratch"}, - %% This is the location of the temp directory where uploaded files will - %% be placed. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - %% BACKEND-SPECIFIC DISPATCH TABLES: - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - %% {webmachine_dispatch, DispatchTable}, - %% Webmachine dispatch table override (ignores static_paths above) - - %% {webmachine_dispatch_fun, {Module, Function}}, - %% A Module:Function() that when evaluated will return a dispatch table - %% for Webmachine, again ignores the static_paths above - - %% {cowboy_dispatch, DispatchTable}, - %% Cowboy dispatch table override (ignores static_paths) - - {cowboy_dispatch_fun, {boss_cowboy_dispacher, build_and_compile}}, - %% A Module:Function() that when evaluated will return a dispatch table - %% for Cowboy, again ignoring the static_paths above. You'll likely - %% want to add a dispatch rule pointing at the standard simple_bridge - %% anchor (unless you're using your own custom anchor): - %% - %% {'_', cowboy_simple_bridge_anchor,[]} - - {dummy, true} -]}, - -%% APPLICATION CONFIGURATIONS - -%% domains - A list of domains to serve the application on -%% static_prefix - The URL prefix of static assets -%% doc_prefix - The URL prefix for developer documentation -{ chicagoboss, [ - {path, "../chicagoboss"}, - {base_url, "/"}, -% {domains, all}, -% {static_prefix, "/static"}, -% {doc_prefix, "/doc"}, - - {dummy, true} -]} -]. diff --git a/frameworks/Erlang/chicagoboss/chicagoboss.dockerfile b/frameworks/Erlang/chicagoboss/chicagoboss.dockerfile deleted file mode 100644 index a41d31961fd..00000000000 --- a/frameworks/Erlang/chicagoboss/chicagoboss.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM erlang:25.1-alpine - -ADD ./ /chicagoboss -WORKDIR /chicagoboss - -RUN rebar get-deps -RUN rebar compile - -EXPOSE 8080 - -CMD erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -config boss -s boss -sname chicagoboss -noshell diff --git a/frameworks/Erlang/chicagoboss/priv/chicagoboss.routes b/frameworks/Erlang/chicagoboss/priv/chicagoboss.routes deleted file mode 100755 index 33133427d50..00000000000 --- a/frameworks/Erlang/chicagoboss/priv/chicagoboss.routes +++ /dev/null @@ -1,28 +0,0 @@ -% Routes file. - -% Formats: -% {"/some/route", [{controller, "Controller"}, {action, "Action"}]}. -% {"/some/route", [{controller, "Controller"}, {action, "Action"}, {id, "42"}]}. -% {"/(some|any)/route/(\\d+)", [{controller, '$1'}, {action, "Action"}, {id, '$2'}]}. -% {"/some/route/(?\\d+)", [{controller, "Controller"}, {action, "Action"}, {id, '$route_id'}]}. -% {"/some/route", [{application, some_app}, {controller, "Controller"}, {action, "Action"}, {id, "42"}]}. -% -% {404, [{controller, "Controller"}, {action, "Action"}]}. -% {404, [{controller, "Controller"}, {action, "Action"}, {id, "42"}]}. -% {404, [{application, some_app}, {controller, "Controller"}, {action, "Action"}, {id, "42"}]}. -% -% Note that routing across applications results in a 302 redirect. - -% Front page -%{"/", [{controller, "plaintext"}, {action, "index"}]}. - -% 404 File Not Found handler -% {404, [{controller, "world"}, {action, "lost"}]}. - -% 500 Internal Error handler (only invoked in production) -% {500, [{controller, "world"}, {action, "calamity"}]}. - -{"/plaintext", [{controller, "world"}, {action, "plaintext"}]}. -{"/json", [{controller, "world"}, {action, "json"}]}. -{"/", [{controller, "world"}, {action, "plaintext"}]}. - diff --git a/frameworks/Erlang/chicagoboss/priv/init/chicagoboss_01_news.erl b/frameworks/Erlang/chicagoboss/priv/init/chicagoboss_01_news.erl deleted file mode 100644 index cda42178bb3..00000000000 --- a/frameworks/Erlang/chicagoboss/priv/init/chicagoboss_01_news.erl +++ /dev/null @@ -1,97 +0,0 @@ --module(chicagoboss_01_news). - --export([init/0, stop/1]). - -% This script is first executed at server startup and should -% return a list of WatchIDs that should be cancelled in the stop -% function below (stop is executed if the script is ever reloaded). -init() -> - {ok, []}. - -stop(ListOfWatchIDs) -> - lists:map(fun boss_news:cancel_watch/1, ListOfWatchIDs). - -%%%%%%%%%%% Ideas -% boss_news:watch("user-42.*", -% fun -% (updated, {Donald, 'location', OldLocation, NewLocation}) -> -% ; -% (updated, {Donald, 'email_address', OldEmail, NewEmail}) -% end), -% -% boss_news:watch("user-*.status", -% fun(updated, {User, 'status', OldStatus, NewStatus}) -> -% Followers = User:followers(), -% lists:map(fun(Follower) -> -% Follower:notify_status_update(User, NewStatus) -% end, Followers) -% end), -% -% boss_news:watch("users", -% fun -% (created, NewUser) -> -% boss_mail:send(?WEBSITE_EMAIL_ADDRESS, -% ?ADMINISTRATOR_EMAIL_ADDRESS, -% "New account!", -% "~p just created an account!~n", -% [NewUser:name()]); -% (deleted, OldUser) -> -% ok -% end), -% -% boss_news:watch("forum_replies", -% fun -% (created, Reply) -> -% OrignalPost = Reply:original_post(), -% OriginalAuthor = OriginalPost:author(), -% case OriginalAuthor:is_online() of -% true -> -% boss_mq:push(OriginalAuthor:comet_channel(), <<"Someone replied!">>); -% false -> -% case OriginalAuthor:likes_email() of -% true -> -% boss_mail:send("website@blahblahblah", -% OriginalAuthor:email_address(), -% "Someone replied!" -% "~p has replied to your post on ~p~n", -% [(Reply:author()):name(), OriginalPost:title()]); -% false -> -% ok -% end -% end; -% (_, _) -> ok -% end), -% -% boss_news:watch("forum_categories", -% fun -% (created, NewCategory) -> -% boss_mail:send(?WEBSITE_EMAIL_ADDRESS, -% ?ADMINISTRATOR_EMAIL_ADDRESS, -% "New category: "++NewCategory:name(), -% "~p has created a new forum category called \"~p\"~n", -% [(NewCategory:created_by()):name(), NewCategory:name()]); -% (_, _) -> ok -% end), -% -% boss_news:watch("forum_category-*.is_deleted", -% fun -% (updated, {ForumCategory, 'is_deleted', false, true}) -> -% ; -% (updated, {ForumCategory, 'is_deleted', true, false}) -> -% end). - -% Invoking the API directly: -%boss_news:deleted("person-42", OldAttrs), -%boss_news:updated("person-42", OldAttrs, NewAttrs), -%boss_news:created("person-42", NewAttrs) - -% Invoking the API via HTTP (with the admin application installed): -% POST /admin/news_api/deleted/person-42 -% old[status] = something - -% POST /admin/news_api/updated/person-42 -% old[status] = blah -% new[status] = barf - -% POST /admin/news_api/created/person-42 -% new[status] = something diff --git a/frameworks/Erlang/chicagoboss/priv/rebar/boss_plugin.erl b/frameworks/Erlang/chicagoboss/priv/rebar/boss_plugin.erl deleted file mode 100644 index 6e14b7f0921..00000000000 --- a/frameworks/Erlang/chicagoboss/priv/rebar/boss_plugin.erl +++ /dev/null @@ -1,191 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Jose Luis Gordo Romero -%%% @doc Chicago Boss rebar plugin -%%% Manage compilation/configuration/scripts stuff the rebar way -%%% @end -%%%------------------------------------------------------------------- --module(boss_plugin). - --export([boss/2, - pre_compile/2, - pre_eunit/2]). - --define(BOSS_PLUGIN_CLIENT_VERSION, 1). --define(BOSS_CONFIG_FILE, "boss.config"). --define(BOSS_TEST_CONFIG_FILE, "boss.test.config"). - -%% ==================================================================== -%% Public API -%% ==================================================================== - -%%-------------------------------------------------------------------- -%% @doc boss command -%% @spec boss(_Config, _AppFile) -> ok | {error, Reason} -%% Boss enabled rebar commands, usage: -%% ./rebar boss c=command -%% @end -%%-------------------------------------------------------------------- -boss(RebarConf, AppFile) -> - case is_base_dir(RebarConf) of - true -> - Command = rebar_config:get_global(RebarConf, c, "help"), - {ok, BossConf} = init(RebarConf, AppFile, Command), - case boss_rebar:run(?BOSS_PLUGIN_CLIENT_VERSION, Command, RebarConf, BossConf, AppFile) of - {error, command_not_found} -> - io:format("ERROR: boss command not found.~n"), - boss_rebar:help(), - halt(1); - {error, Reason} -> - io:format("ERROR: executing ~s task: ~s~n", [Command, Reason]), - halt(1); - ok -> ok - end; - false -> ok - end. - -%%-------------------------------------------------------------------- -%% @doc initializes the rebar boss connector plugin -%% @spec init(Config, AppFile) -> {ok, BossConf} | {error, Reason} -%% Set's the ebin cb_apps and loads the connector -%% @end -%%-------------------------------------------------------------------- -init(RebarConf, AppFile, Command) -> - %% Compile and load the boss_rebar code, this can't be compiled - %% as a normal boss lib without the rebar source dep - %% The load of ./rebar boss: - %% - Rebar itself searchs in rebar.config for {plugin_dir, ["priv/rebar"]}. - %% - Rebar itself compile this plugin and adds it to the execution chain - %% - This plugin compiles and loads the boss_rebar code in ["cb/priv/rebar"], - %% so we can extend/bugfix/tweak the framework without the need of manually - %% recopy code to user apps - {BossConf, BossConfFile} = boss_config(Command), - BossPath = case boss_config_value(boss, path, BossConf) of - {error, _} -> - filename:join([rebar_config:get_xconf(RebarConf, base_dir, undefined), "deps", "boss"]); - Val -> Val - end, - RebarErls = rebar_utils:find_files(filename:join([BossPath, "priv", "rebar"]), ".*\\.erl\$"), - - rebar_log:log(debug, "Auto-loading boss rebar modules ~p~n", [RebarErls]), - - lists:map(fun(F) -> - case compile:file(F, [binary]) of - error -> - io:format("FATAL: Failed compilation of ~s module~n", [F]), - halt(1); - {ok, M, Bin} -> - {module, _} = code:load_binary(M, F, Bin), - rebar_log:log(debug, "Loaded ~s~n", [M]) - end - end, RebarErls), - - %% add all cb_apps defined in config file to code path - %% including the deps ebin dirs - - case is_base_dir(RebarConf) of - true -> - code:add_paths(["ebin" | filelib:wildcard(rebar_config:get_xconf(RebarConf, base_dir, undefined) ++ "/deps/*/ebin")]); - false -> - code:add_paths(filelib:wildcard(rebar_utils:get_cwd() ++ "/../*/ebin")) - end, - %% Load the config in the environment - boss_rebar:init_conf(BossConf), - - {ok, BossConf}. - -%%-------------------------------------------------------------------- -%% @doc pre_compile hook -%% @spec pre_compile(_Config, AppFile) -> ok | {error, Reason} -%% Pre compile hook, compile the boss way -%% Compatibility hook, the normal ./rebar compile command works, -%% but only calls the ./rebar boss c=compile and halts (default -%% rebar task never hits) -%% @end -%%-------------------------------------------------------------------- -pre_compile(RebarConf, AppFile) -> - case is_boss_app(AppFile) orelse is_base_dir(RebarConf) of - true -> - {ok, BossConf} = init(RebarConf, AppFile, "compile"), - boss_rebar:run(?BOSS_PLUGIN_CLIENT_VERSION, compile, RebarConf, BossConf, AppFile), - halt(0); - false -> ok - end. - -%%-------------------------------------------------------------------- -%% @doc pre_eunit hook -%% @spec pre_eunit(RebarConf, AppFile) -> ok | {error, Reason} -%% Pre eunit hook, .eunit compilation the boss way -%% Compatibility hook, the normal ./rebar eunit command works, -%% but only calls the ./rebar boss c=test_eunit and halts -%% (default rebar task never hits) -%% @end -%%-------------------------------------------------------------------- -pre_eunit(RebarConf, AppFile) -> - case is_boss_app(AppFile) orelse is_base_dir(RebarConf) of - true -> - {ok, BossConf} = init(RebarConf, AppFile, "test_eunit"), - boss_rebar:run(?BOSS_PLUGIN_CLIENT_VERSION, test_eunit, RebarConf, BossConf, AppFile), - halt(0); - false -> ok - end. - -%% =================================================================== -%% Internal functions -%% =================================================================== - -is_boss_app(Filename)-> - BossFileForApp = filename:join([filename:dirname(Filename), "..", "boss.config"]), - filelib:is_file(BossFileForApp). - -%% Checks if the current dir (rebar execution) is the base_dir -%% Used to prevent run boss tasks in deps directory -is_base_dir(RebarConf) -> - filename:absname(rebar_utils:get_cwd()) =:= rebar_config:get_xconf(RebarConf, base_dir, undefined). - -%% Gets the boss.config central configuration file -boss_config(Command) -> - IsTest = lists:prefix("test_", Command), - BossConfFile = get_config_file(IsTest), - ConfigData = file:consult(BossConfFile), - validate_config_data(BossConfFile, ConfigData). - -get_config_file(false) -> - ?BOSS_CONFIG_FILE; -get_config_file(true) -> - case file:read_file_info(?BOSS_TEST_CONFIG_FILE) of - {ok, _} -> ?BOSS_TEST_CONFIG_FILE; - _ -> ?BOSS_CONFIG_FILE - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -validate_config_data(BossConfFile, {error, {Line, _Mod, [Term|_]}}) -> - io:format("FATAL: Config file ~p has a syntax error on line ~p, ~n ~p ~n~n", - [BossConfFile, Line, Term]), - halt(1); -validate_config_data(BossConfFile, {error, enoent}) -> - io:format("FATAL: Config file ~p not found.~n", [BossConfFile]), - halt(1); -validate_config_data(BossConfFile, {ok, [BossConfig]}) -> - {BossConfig, BossConfFile}. - - - -%%-------------------------------------------------------------------- -%% @doc Get Boss config value app, key -%% @spec boss_config_value(App, Key) -> Value | {error, Reason} -%% Searchs in boss config for a given App and Key -%% @end -%%-------------------------------------------------------------------- -boss_config_value(App, Key, BossConfig) -> - case lists:keyfind(App, 1, BossConfig) of - false -> - {error, boss_config_app_not_found}; - {App, AppConfig} -> - case lists:keyfind(Key, 1, AppConfig) of - false -> - {error, boss_config_app_setting_not_found}; - {Key, KeyConfig} -> - KeyConfig - end - end. diff --git a/frameworks/Erlang/chicagoboss/rebar.config b/frameworks/Erlang/chicagoboss/rebar.config deleted file mode 100644 index 6b14cce62ef..00000000000 --- a/frameworks/Erlang/chicagoboss/rebar.config +++ /dev/null @@ -1,7 +0,0 @@ -{deps, [ - {boss, ".*", {git, "git://github.com/ChicagoBoss/ChicagoBoss.git", {tag, "0.9.0"}}} -]}. -{plugin_dir, ["priv/rebar"]}. -{plugins, [boss_plugin]}. -{eunit_compile_opts, [{src_dirs, ["src/test"]}]}. -{lib_dirs, ["../ChicagoBoss/deps/elixir/lib"]}. diff --git a/frameworks/Erlang/chicagoboss/src/chicagoboss.app.src b/frameworks/Erlang/chicagoboss/src/chicagoboss.app.src deleted file mode 100644 index ea172e406a8..00000000000 --- a/frameworks/Erlang/chicagoboss/src/chicagoboss.app.src +++ /dev/null @@ -1,8 +0,0 @@ -{application, chicagoboss, [ - {description, "My Awesome Web Framework"}, - {vsn, "0.0.1"}, - {modules, []}, - {registered, []}, - {applications, [kernel, stdlib, crypto]}, - {env, []} - ]}. diff --git a/frameworks/Erlang/chicagoboss/src/controller/chicagoboss_world_controller.erl b/frameworks/Erlang/chicagoboss/src/controller/chicagoboss_world_controller.erl deleted file mode 100755 index 9174bc40aa5..00000000000 --- a/frameworks/Erlang/chicagoboss/src/controller/chicagoboss_world_controller.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(chicagoboss_world_controller, [Req]). --compile(export_all). - -plaintext('GET', []) -> - {output, "Hello, world!", [{"Content-Type", "text/plain"}]}. - -json('GET', []) -> - {json, [{message, "Hello, world!"}]}. diff --git a/frameworks/Erlang/chicagoboss/src/mail/chicagoboss_incoming_mail_controller.erl b/frameworks/Erlang/chicagoboss/src/mail/chicagoboss_incoming_mail_controller.erl deleted file mode 100644 index 05bf159587d..00000000000 --- a/frameworks/Erlang/chicagoboss/src/mail/chicagoboss_incoming_mail_controller.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(chicagoboss_incoming_mail_controller). --compile(export_all). - -authorize_(User, DomainName, IPAddress) -> - true. - -% post(FromAddress, Message) -> -% ok. diff --git a/frameworks/Erlang/chicagoboss/src/mail/chicagoboss_outgoing_mail_controller.erl b/frameworks/Erlang/chicagoboss/src/mail/chicagoboss_outgoing_mail_controller.erl deleted file mode 100644 index c4af9cbbf09..00000000000 --- a/frameworks/Erlang/chicagoboss/src/mail/chicagoboss_outgoing_mail_controller.erl +++ /dev/null @@ -1,12 +0,0 @@ --module(chicagoboss_outgoing_mail_controller). --compile(export_all). - -%% See http://www.chicagoboss.org/api-mail-controller.html for what should go in here - -test_message(FromAddress, ToAddress, Subject) -> - Headers = [ - {"Subject", Subject}, - {"To", ToAddress}, - {"From", FromAddress} - ], - {ok, FromAddress, ToAddress, Headers, [{address, ToAddress}]}. diff --git a/frameworks/Erlang/elli/README.md b/frameworks/Erlang/elli/README.md deleted file mode 100644 index 7389fe5b64f..00000000000 --- a/frameworks/Erlang/elli/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Elli Benchmarking Test - -This is the Elli portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -### JSON Encoding Test - -* [JSON test controller](src/elli_bench_cb.erl) - - -### Data-Store/Database Mapping Test - -* [DB test controller](src/elli_bench_cb.erl) - - -## Infrastructure Software Versions -The tests were run with: - -* [Elli](git://github.com/knutin/elli) -* [Erlang R16B](http://www.erlang.org/) -* [MySQL 5.5.29](https://dev.mysql.com/) - -## Test URLs -### JSON Encoding Test - -http://localhost/json - -### Data-Store/Database Mapping Test - -http://localhost/db - -### Variable Query Test - -http://localhost/db?queries=2 diff --git a/frameworks/Erlang/elli/benchmark_config.json b/frameworks/Erlang/elli/benchmark_config.json deleted file mode 100644 index ce58700f3e1..00000000000 --- a/frameworks/Erlang/elli/benchmark_config.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "framework": "elli", - "tests": [{ - "default": { - "plaintext_url":"/plaintext", - "json_url": "/json", - "db_url": "/db", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "elli", - "language": "Erlang", - "flavor": "None", - "orm": "Raw", - "platform": "beam", - "webserver": "elli", - "os": "Linux", - "database_os": "Linux", - "display_name": "elli", - "notes": "", - "tags": ["broken"], - "versus": "" - }}] -} diff --git a/frameworks/Erlang/elli/elli.dockerfile b/frameworks/Erlang/elli/elli.dockerfile deleted file mode 100644 index 7e4d305e664..00000000000 --- a/frameworks/Erlang/elli/elli.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM erlang:25.1 - -WORKDIR /elli -COPY src src -COPY rebar.config rebar.config - -RUN rebar get-deps -RUN rebar compile - -EXPOSE 8080 - -CMD erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s elli_bench -noshell diff --git a/frameworks/Erlang/elli/rebar.config b/frameworks/Erlang/elli/rebar.config deleted file mode 100644 index cfc0e615bcf..00000000000 --- a/frameworks/Erlang/elli/rebar.config +++ /dev/null @@ -1,6 +0,0 @@ -{deps, - [ - {jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "1.1.1"}}}, - {emysql, ".*", {git, "https://github.com/deadtrickster/Emysql.git", "52b802098322aad372198b9f5fa9ae9a4c758ad1"}}, - {elli, ".*", {git, "https://github.com/elli-lib/elli.git", {tag, "3.3.0"}}} - ]}. diff --git a/frameworks/Erlang/elli/src/elli_bench.app.src b/frameworks/Erlang/elli/src/elli_bench.app.src deleted file mode 100644 index aa4a1b58ed4..00000000000 --- a/frameworks/Erlang/elli/src/elli_bench.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application, elli_bench, - [ - {description, ""}, - {vsn, "1"}, - {registered, []}, - {applications, [ - kernel, - stdlib - ]}, - {mod, { elli_bench_app, []}}, - {env, []} - ]}. diff --git a/frameworks/Erlang/elli/src/elli_bench.erl b/frameworks/Erlang/elli/src/elli_bench.erl deleted file mode 100644 index ef4a7526b12..00000000000 --- a/frameworks/Erlang/elli/src/elli_bench.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(elli_bench). --export([start/0]). - -start() -> - application:start(elli_bench). diff --git a/frameworks/Erlang/elli/src/elli_bench_app.erl b/frameworks/Erlang/elli/src/elli_bench_app.erl deleted file mode 100644 index f3d3a4eb5d7..00000000000 --- a/frameworks/Erlang/elli/src/elli_bench_app.erl +++ /dev/null @@ -1,16 +0,0 @@ --module(elli_bench_app). - --behaviour(application). - -%% Application callbacks --export([start/2, stop/1]). - -%% =================================================================== -%% Application callbacks -%% =================================================================== - -start(_StartType, _StartArgs) -> - elli_bench_sup:start_link(). - -stop(_State) -> - ok. diff --git a/frameworks/Erlang/elli/src/elli_bench_cb.erl b/frameworks/Erlang/elli/src/elli_bench_cb.erl deleted file mode 100644 index 7fc5bb39e4e..00000000000 --- a/frameworks/Erlang/elli/src/elli_bench_cb.erl +++ /dev/null @@ -1,61 +0,0 @@ --module(elli_bench_cb). --export([handle/2, handle_event/3]). - --include_lib("elli/include/elli.hrl"). --behaviour(elli_handler). - -handle(Req, _Args) -> - %% Delegate to our handler function - handle(Req#req.method, elli_request:path(Req), Req). - -%% Plaintext test route -handle('GET', [<<"plaintext">>], _Req) -> - %% Reply with a normal response. 'ok' can be used instead of '200' - %% to signal success. - {ok, [{<<"Server">>, <<"elli">>}, {<<"Date">>, httpd_util:rfc1123_date()}, {<<"Content-Type">>, <<"text/plain">>}], <<"Hello, World!">>}; - -%% Json test route -handle('GET',[<<"json">>], _Req) -> - %% Reply with a normal response. 'ok' can be used instead of '200' - %% to signal success. - {ok, [{<<"Server">>, <<"elli">>}, {<<"Date">>, httpd_util:rfc1123_date()}, {<<"Content-Type">>, <<"application/json">>}], jiffy:encode({[{<<"message">>, <<"Hello, World!">>}]})}; - -%% db test route (Single Database Query) -handle('GET',[<<"db">>], Req) -> - random:seed(erlang:now()), - JSON = case elli_request:get_arg(<<"queries">>, Req) of - undefined -> - {result_packet, _, _, [[ID, Rand]], _} = emysql:execute(test_pool, db_stmt, [random:uniform(10000)]), - [{[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]}]; - N -> - I = list_to_integer(binary_to_list(N)), - Res = [ {[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]} || - {result_packet, _, _, [[ID, Rand]], _} <- [emysql:execute(test_pool, db_stmt, [random:uniform(10000)]) || _ <- lists:seq(1, I) ]], - Res - end, - {ok, [{<<"Server">>, <<"elli">>}, {<<"Date">>, httpd_util:rfc1123_date()}, {<<"Content-Type">>, <<"application/json">>}], jiffy:encode(lists:nth(1,JSON))}; - -%% TODO : Finish this function with correct logic. -%% Please check TFB document -%% Multiple query test route -% handle('GET',[<<"query">>], Req) -> -% random:seed(erlang:now()), -% JSON = case elli_request:get_arg(<<"queries">>, Req) of -% undefined -> -% {result_packet, _, _, [[ID, Rand]], _} = emysql:execute(test_pool, db_stmt, [random:uniform(10000)]), -% [{[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]}]; -% N -> -% I = list_to_integer(binary_to_list(N)), -% Res = [ {[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]} || -% {result_packet, _, _, [[ID, Rand]], _} <- [emysql:execute(test_pool, db_stmt, [random:uniform(10000)]) || _ <- lists:seq(1, I) ]], -% Res -% end, -% {ok, [{<<"Content-Type">>, <<"application/json">>}], jiffy:encode(JSON)}; - -handle(_, _, _Req) -> - {404, [], <<"Not Found">>}. - -%% @doc: Handle request events, like request completed, exception -%% thrown, client timeout, etc. Must return 'ok'. -handle_event(_Event, _Data, _Args) -> - ok. diff --git a/frameworks/Erlang/elli/src/elli_bench_sup.erl b/frameworks/Erlang/elli/src/elli_bench_sup.erl deleted file mode 100644 index 6da7b7571d7..00000000000 --- a/frameworks/Erlang/elli/src/elli_bench_sup.erl +++ /dev/null @@ -1,46 +0,0 @@ --module(elli_bench_sup). - --behaviour(supervisor). - -%% API --export([start_link/0]). - -%% Supervisor callbacks --export([init/1]). - -%% Helper macro for declaring children of supervisor --define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). - -%% =================================================================== -%% API functions -%% =================================================================== - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -%% =================================================================== -%% Supervisor callbacks -%% =================================================================== - -%% CAUTION : Assign big number to db pool will fail travis ci. -%% Original value was 5000, too big! Even 512 crashes! keep 256 -%% till travis-ci environment accepts bigger size of db pool. - -init([]) -> - crypto:start(), - application:start(emysql), - emysql:add_pool(test_pool, 256, - "benchmarkdbuser", "benchmarkdbpass", "tfb-database", 3306, - "hello_world", utf8), - emysql:prepare(db_stmt, <<"SELECT * FROM World where id = ?">>), - ElliOpts = [{callback, elli_bench_cb}, {port, 8080}], - ElliSpec = { - fancy_http, - {elli, start_link, [ElliOpts]}, - permanent, - 256, - worker, - [elli]}, - - {ok, { {one_for_one, 5, 10}, [ElliSpec]} }. - diff --git a/frameworks/FSharp/falco/src/App/Program.fs b/frameworks/FSharp/falco/src/App/Program.fs index 7d6f19e5584..b860a4b9f5b 100644 --- a/frameworks/FSharp/falco/src/App/Program.fs +++ b/frameworks/FSharp/falco/src/App/Program.fs @@ -22,16 +22,13 @@ type Fortune = { id : int message : string } - static member Default = - { id = 0 - message = "Additional fortune added at request time." } - let handleFortunes (connStr : string) : HttpHandler = fun ctx -> task { use conn = new NpgsqlConnection(connStr) let! data = conn.QueryAsync("SELECT id, message FROM fortune") let fortunes = data.AsList() - fortunes.Add(Fortune.Default) + fortunes.Add({ id = 0 + message = "Additional fortune added at request time." }) let sortedFortunes = fortunes diff --git a/frameworks/FSharp/frank/src/App/Program.fs b/frameworks/FSharp/frank/src/App/Program.fs index 9f0036ab963..6fb891b3b31 100644 --- a/frameworks/FSharp/frank/src/App/Program.fs +++ b/frameworks/FSharp/frank/src/App/Program.fs @@ -37,7 +37,6 @@ let text' (msg:string): HttpContext -> Task = ctx.Response.Body.WriteAsync(bytes, 0, bytes.Length) // Pulled from Giraffe example -let extra = { id = 0; message = "Additional fortune added at request time." } let fortunes' : HttpHandler = fun _ ctx -> task { @@ -46,7 +45,7 @@ let fortunes' : HttpHandler = let view = let xs = data.AsList() - xs.Add extra + xs.Add { id = 0; message = "Additional fortune added at request time." } xs.Sort FortuneComparer HtmlViews.fortunes xs diff --git a/frameworks/FSharp/giraffe/src/App/Program.fs b/frameworks/FSharp/giraffe/src/App/Program.fs index f7d62db7d33..84be51adb85 100644 --- a/frameworks/FSharp/giraffe/src/App/Program.fs +++ b/frameworks/FSharp/giraffe/src/App/Program.fs @@ -117,11 +117,6 @@ module HttpHandlers = open Dapper open Npgsql - let private extra = { - id = 0 - message = "Additional fortune added at request time." - } - let fortunes: HttpHandler = fun _ ctx -> task { @@ -133,7 +128,7 @@ module HttpHandlers = let view = let xs = data.AsList () - xs.Add extra + xs.Add { id = 0; message = "Additional fortune added at request time." } xs.Sort FortuneComparer HtmlViews.fortunes xs diff --git a/frameworks/FSharp/oxpecker/src/App/Program.fs b/frameworks/FSharp/oxpecker/src/App/Program.fs index ce301a87b89..f9de82aa4c7 100644 --- a/frameworks/FSharp/oxpecker/src/App/Program.fs +++ b/frameworks/FSharp/oxpecker/src/App/Program.fs @@ -10,12 +10,6 @@ module HttpHandlers = open SpanJson open Oxpecker.ViewEngine - let private extra = - { - id = 0 - message = "Additional fortune added at request time." - } - let private fortunesHeadAndTail = (fun (content: HtmlElement) -> html() { @@ -35,7 +29,7 @@ module HttpHandlers = ) |> RenderHelpers.prerender let rec private renderFortunes (ctx: HttpContext) (data: ResizeArray) = - data.Add extra + data.Add { id = 0; message = "Additional fortune added at request time." } data.Sort FortuneComparer RenderHelpers.CombinedElement(fortunesHeadAndTail, data) |> ctx.WriteHtmlViewChunked diff --git a/frameworks/FSharp/suave/benchmark_config.json b/frameworks/FSharp/suave/benchmark_config.json index e6ca9696fa2..1f90814a960 100755 --- a/frameworks/FSharp/suave/benchmark_config.json +++ b/frameworks/FSharp/suave/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "suave", + "maintainers": ["ademar"], "tests": [ { "default": { @@ -14,7 +15,7 @@ "flavor": "None", "orm": "None", "platform": ".NET", - "webserver": "None", + "webserver": "Suave", "os": "Linux", "database_os": "Linux", "display_name": "Suave", diff --git a/frameworks/FSharp/suave/src/App/App.fsproj b/frameworks/FSharp/suave/src/App/App.fsproj index 3b838c61367..043da71dcc0 100755 --- a/frameworks/FSharp/suave/src/App/App.fsproj +++ b/frameworks/FSharp/suave/src/App/App.fsproj @@ -1,8 +1,8 @@ - + Exe - net7.0 + net10.0 true true @@ -13,8 +13,7 @@
- - + diff --git a/frameworks/FSharp/suave/src/App/Program.fs b/frameworks/FSharp/suave/src/App/Program.fs index 817ae5798d6..9a30608b732 100755 --- a/frameworks/FSharp/suave/src/App/Program.fs +++ b/frameworks/FSharp/suave/src/App/Program.fs @@ -1,6 +1,6 @@ open Suave -open Suave.Filters open Suave.Operators +open Suave.Router open Suave.Json open System.Net @@ -9,11 +9,10 @@ open System.Runtime.Serialization [] type JsonMessage = { [] message: string } -let app = - choose [ - path "/plaintext" >=> Writers.setMimeType "text/plain; charset=utf-8" >=> Successful.OK "Hello, World!" - path "/json" >=> Writers.setMimeType "application/json; charset=utf-8" >=> Successful.ok (toJson { message = "Hello, World!"}) - ] +let app : WebPart = router { + get "/plaintext" (Writers.setMimeType "text/plain; charset=utf-8" >=> Successful.OK "Hello, World!") + get "/json" (Writers.setMimeType "application/json; charset=utf-8" >=> Successful.ok (toJson { message = "Hello, World!"})) + } let cfg = { defaultConfig with bindings = [ HttpBinding.create HTTP IPAddress.Any 8080us ] } diff --git a/frameworks/FSharp/suave/suave.dockerfile b/frameworks/FSharp/suave/suave.dockerfile index 29879f01d3c..5bd60dd88b2 100644 --- a/frameworks/FSharp/suave/suave.dockerfile +++ b/frameworks/FSharp/suave/suave.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.100 +FROM mcr.microsoft.com/dotnet/sdk:10.0 WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out diff --git a/frameworks/FSharp/zebra/src/App/Program.fs b/frameworks/FSharp/zebra/src/App/Program.fs index 8c871767882..6e7b0261bf9 100644 --- a/frameworks/FSharp/zebra/src/App/Program.fs +++ b/frameworks/FSharp/zebra/src/App/Program.fs @@ -73,7 +73,6 @@ module View = ] ] |> compileDoc - let extra = { id = 0; message = "Additional fortune added at request time." } let FortuneComparer = { new IComparer with member self.Compare(a,b) = String.CompareOrdinal(a.message, b.message) } @@ -98,7 +97,7 @@ let main args = let fortunes = let xs = data.AsList() - xs.Add View.extra + xs.Add { id = 0; message = "Additional fortune added at request time." } xs.Sort View.FortuneComparer xs diff --git a/frameworks/Fortran/fortran.io/benchmark_config.json b/frameworks/Fortran/fortran.io/benchmark_config.json index 3b22e097258..2351252f4e4 100755 --- a/frameworks/Fortran/fortran.io/benchmark_config.json +++ b/frameworks/Fortran/fortran.io/benchmark_config.json @@ -18,7 +18,8 @@ "database_os": "Linux", "display_name": "Fortran.io", "notes": "", - "versus": "None" + "versus": "None", + "tags": [ "broken" ] } } ] diff --git a/frameworks/Fortran/fortran.io/nginx.conf b/frameworks/Fortran/fortran.io/nginx.conf index 232866a3457..6b5a432e8f0 100644 --- a/frameworks/Fortran/fortran.io/nginx.conf +++ b/frameworks/Fortran/fortran.io/nginx.conf @@ -1,7 +1,7 @@ user nginx; worker_processes auto; -error_log /var/log/nginx/error.log notice; +error_log stderr error; pid /var/run/nginx.pid; @@ -13,11 +13,7 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; + access_log off; sendfile on; keepalive_timeout 65; diff --git a/frameworks/Go/fiber/benchmark_config.json b/frameworks/Go/fiber/benchmark_config.json index 7658b472d6a..850360410d9 100644 --- a/frameworks/Go/fiber/benchmark_config.json +++ b/frameworks/Go/fiber/benchmark_config.json @@ -1,53 +1,103 @@ { "framework": "fiber", - "tests": [{ - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?q=", - "fortune_url": "/fortunes", - "cached_query_url": "/cached-worlds?q=", - "update_url": "/update?q=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "fiber", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Fiber", - "notes": "", - "versus": "go" - }, - "prefork": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?q=", - "fortune_url": "/fortunes", - "cached_query_url": "/cached-worlds?q=", - "update_url": "/update?q=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "fiber", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Fiber prefork", - "notes": "", - "versus": "go" + "tests": [ + { + "default": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?q=", + "update_url": "/update?q=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "fiber-v3", + "language": "Go", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Fiber v3", + "notes": "", + "versus": "go" + }, + "v2": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?q=", + "update_url": "/update?q=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "fiber-v2", + "language": "Go", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Fiber v2", + "notes": "", + "versus": "go" + }, + "v3-prefork": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?q=", + "update_url": "/update?q=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "fiber-v3-prefork", + "language": "Go", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Fiber v3 prefork", + "notes": "", + "versus": "go" + }, + "v2-prefork": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?q=", + "update_url": "/update?q=", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "fiber-v2-prefork", + "language": "Go", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Fiber v2 prefork", + "notes": "", + "versus": "go" + } } - }] + ] } \ No newline at end of file diff --git a/frameworks/Go/fiber/fiber-prefork.dockerfile b/frameworks/Go/fiber/fiber-prefork.dockerfile deleted file mode 100644 index 13e45eb4cba..00000000000 --- a/frameworks/Go/fiber/fiber-prefork.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM golang:1.24.2-alpine as builder - -WORKDIR /fiber - -COPY ./src /fiber - -RUN go mod download && \ - go generate -x ./templates && \ - GOAMD64=v3 go build -ldflags="-s -w" -o app . - -FROM alpine:latest - -WORKDIR /fiber - -COPY --from=builder /fiber/app . - -EXPOSE 8080 - -CMD ./app -prefork diff --git a/frameworks/Go/fiber/fiber-v2-prefork.dockerfile b/frameworks/Go/fiber/fiber-v2-prefork.dockerfile new file mode 100644 index 00000000000..de2e4971209 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v2-prefork.dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.25.6-alpine as builder + +WORKDIR /fiber + +COPY ./fiber-v2 /fiber + +RUN go mod download && \ + go install github.com/valyala/quicktemplate/qtc@latest && \ + qtc && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . + +FROM alpine:latest + +WORKDIR /fiber + +COPY --from=builder /fiber/app . + +EXPOSE 8080 + +CMD ./app -prefork diff --git a/frameworks/Go/fiber/fiber-v2.dockerfile b/frameworks/Go/fiber/fiber-v2.dockerfile new file mode 100644 index 00000000000..60de9d3a38f --- /dev/null +++ b/frameworks/Go/fiber/fiber-v2.dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.25.6-alpine as builder + +WORKDIR /fiber + +COPY ./fiber-v2 /fiber + +RUN go mod download && \ + go install github.com/valyala/quicktemplate/qtc@latest && \ + qtc && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . + +FROM alpine:latest + +WORKDIR /fiber + +COPY --from=builder /fiber/app . + +EXPOSE 8080 + +CMD ./app diff --git a/frameworks/Go/fiber/fiber-v2/go.mod b/frameworks/Go/fiber/fiber-v2/go.mod new file mode 100644 index 00000000000..a5cef177463 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v2/go.mod @@ -0,0 +1,28 @@ +module fiber-v2/app + +go 1.25.0 + +require ( + github.com/goccy/go-json v0.10.5 + github.com/gofiber/fiber/v2 v2.52.12 + github.com/jackc/pgx/v5 v5.8.0 + github.com/valyala/quicktemplate v1.8.0 +) + +require ( + github.com/andybalholm/brotli v1.2.0 // indirect + github.com/clipperhouse/uax29/v2 v2.6.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/klauspost/compress v1.18.4 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.69.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.33.0 // indirect +) diff --git a/frameworks/Go/fiber/fiber-v2/go.sum b/frameworks/Go/fiber/fiber-v2/go.sum new file mode 100644 index 00000000000..5fab16a1818 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v2/go.sum @@ -0,0 +1,55 @@ +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= +github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= +github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= +github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= +github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/fiber/fiber-v2/server.go b/frameworks/Go/fiber/fiber-v2/server.go new file mode 100644 index 00000000000..f4a75a97d24 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v2/server.go @@ -0,0 +1,313 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "os" + "runtime" + "sort" + "sync" + + "github.com/goccy/go-json" + "github.com/gofiber/fiber/v2" + + "fiber-v2/app/templates" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +var ( + db *pgxpool.Pool + cachedWorlds Worlds +) + +const ( + queryparam = "q" + helloworld = "Hello, World!" + worldcount = 10000 + worldselectsql = "SELECT id, randomNumber FROM World WHERE id = $1" + worldupdatesql = "UPDATE World SET randomNumber = $1 WHERE id = $2" + worldcachesql = "SELECT * FROM World LIMIT $1" + fortuneselectsql = "SELECT id, message FROM Fortune" + pathJSON = "/json" + pathDB = "/db" + pathQueries = "/queries" + pathCache = "/cached-worlds" + pathFortunes = "/fortunes" + pathUpdate = "/update" + pathText = "/plaintext" +) + +func main() { + initDatabase() + + config := fiber.Config{ + CaseSensitive: true, + StrictRouting: true, + DisableHeaderNormalizing: true, + ServerHeader: "go", + JSONEncoder: json.Marshal, + JSONDecoder: json.Unmarshal, + } + + for i := range os.Args[1:] { + if os.Args[1:][i] == "-prefork" { + config.Prefork = true + } + } + + app := fiber.New(config) + + app.Use(func(c *fiber.Ctx) error { + switch c.Path() { + case pathJSON: + jsonHandler(c) + case pathDB: + dbHandler(c) + case pathQueries: + queriesHandler(c) + case pathCache: + cachedHandler(c) + case pathFortunes: + templateHandler(c) + case pathUpdate: + updateHandler(c) + case pathText: + plaintextHandler(c) + } + return nil + }) + + log.Fatal(app.Listen(":8080")) +} + +// Message ... +type Message struct { + Message string `json:"message"` +} + +// Worlds ... +type Worlds []World + +// World ... +type World struct { + ID int32 `json:"id"` + RandomNumber int32 `json:"randomNumber"` +} + +// JSONpool ... +var JSONpool = sync.Pool{ + New: func() interface{} { + return new(Message) + }, +} + +// AcquireJSON ... +func AcquireJSON() *Message { + return JSONpool.Get().(*Message) +} + +// ReleaseJSON ... +func ReleaseJSON(json *Message) { + json.Message = "" + JSONpool.Put(json) +} + +// WorldPool ... +var WorldPool = sync.Pool{ + New: func() interface{} { + return new(World) + }, +} + +// AcquireWorld ... +func AcquireWorld() *World { + return WorldPool.Get().(*World) +} + +// ReleaseWorld ... +func ReleaseWorld(w *World) { + w.ID = 0 + w.RandomNumber = 0 + WorldPool.Put(w) +} + +// WorldsPool ... +var WorldsPool = sync.Pool{ + New: func() interface{} { + return make(Worlds, 0, 500) + }, +} + +// AcquireWorlds ... +func AcquireWorlds() Worlds { + return WorldsPool.Get().(Worlds) +} + +// ReleaseWorlds ...ReleaseWorlds +func ReleaseWorlds(w Worlds) { + w = w[:0] + WorldsPool.Put(w) +} + +// initDatabase : +func initDatabase() { + maxConn := runtime.NumCPU() * 4 + if fiber.IsChild() { + maxConn = 5 + } + + var err error + db, err = pgxpool.New(context.Background(), + fmt.Sprintf( + "host=%s port=%d user=%s password=%s dbname=%s pool_max_conns=%d", + "tfb-database", 5432, + "benchmarkdbuser", + "benchmarkdbpass", + "hello_world", + maxConn, + )) + if err != nil { + panic(err) + } + populateCache() +} + +// this will populate the cached worlds for the cache test +func populateCache() { + worlds := make(Worlds, worldcount) + rows, err := db.Query(context.Background(), worldcachesql, worldcount) + if err != nil { + panic(err) + } + for i := 0; i < worldcount; i++ { + w := &worlds[i] + if !rows.Next() { + break + } + if err := rows.Scan(&w.ID, &w.RandomNumber); err != nil { + panic(err) + } + //db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + } + cachedWorlds = worlds +} + +// jsonHandler : +func jsonHandler(c *fiber.Ctx) error { + m := AcquireJSON() + m.Message = helloworld + c.JSON(&m) + ReleaseJSON(m) + return nil +} + +// dbHandler : +func dbHandler(c *fiber.Ctx) error { + w := AcquireWorld() + db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + c.JSON(&w) + ReleaseWorld(w) + return nil +} + +// Frameworks/Go/fasthttp/src/server-postgresql/server.go#104 +func templateHandler(c *fiber.Ctx) error { + rows, _ := db.Query(context.Background(), fortuneselectsql) + + var f templates.Fortune + fortunes := make([]templates.Fortune, 0) + for rows.Next() { + _ = rows.Scan(&f.ID, &f.Message) + fortunes = append(fortunes, f) + } + rows.Close() + fortunes = append(fortunes, templates.Fortune{ + Message: "Additional fortune added at request time.", + }) + + sort.Slice(fortunes, func(i, j int) bool { + return fortunes[i].Message < fortunes[j].Message + }) + + c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8) + + templates.WriteFortunePage(c.Context(), fortunes) + return nil +} + +// queriesHandler : +func queriesHandler(c *fiber.Ctx) error { + n := QueriesCount(c) + worlds := AcquireWorlds()[:n] + for i := 0; i < n; i++ { + w := &worlds[i] + db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + } + c.JSON(&worlds) + ReleaseWorlds(worlds) + return nil +} + +// updateHandler : +func updateHandler(c *fiber.Ctx) error { + n := QueriesCount(c) + worlds := AcquireWorlds()[:n] + for i := 0; i < n; i++ { + w := &worlds[i] + db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + w.RandomNumber = int32(RandomWorld()) + } + // sorting is required for insert deadlock prevention. + sort.Slice(worlds, func(i, j int) bool { + return worlds[i].ID < worlds[j].ID + }) + + batch := pgx.Batch{} + for _, w := range worlds { + batch.Queue(worldupdatesql, w.RandomNumber, w.ID) + } + db.SendBatch(context.Background(), &batch).Close() + c.JSON(&worlds) + ReleaseWorlds(worlds) + + return nil +} + +var helloworldRaw = []byte("Hello, World!") + +// plaintextHandler : +func plaintextHandler(c *fiber.Ctx) error { + return c.Send(helloworldRaw) +} + +// cachedHandler : +func cachedHandler(c *fiber.Ctx) error { + n := QueriesCount(c) + worlds := AcquireWorlds()[:n] + for i := 0; i < n; i++ { + worlds[i] = cachedWorlds[RandomWorld()-1] + } + c.JSON(&worlds) + ReleaseWorlds(worlds) + return nil +} + +// RandomWorld : +func RandomWorld() int { + return rand.Intn(worldcount) + 1 +} + +// QueriesCount : +func QueriesCount(c *fiber.Ctx) int { + n := c.Request().URI().QueryArgs().GetUintOrZero(queryparam) + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + return n +} diff --git a/frameworks/Go/fiber/src/server_test.go b/frameworks/Go/fiber/fiber-v2/server_test.go similarity index 100% rename from frameworks/Go/fiber/src/server_test.go rename to frameworks/Go/fiber/fiber-v2/server_test.go diff --git a/frameworks/Go/fiber/src/templates/fortune.go b/frameworks/Go/fiber/fiber-v2/templates/fortune.go similarity index 100% rename from frameworks/Go/fiber/src/templates/fortune.go rename to frameworks/Go/fiber/fiber-v2/templates/fortune.go diff --git a/frameworks/Go/fiber/src/templates/fortune.qtpl b/frameworks/Go/fiber/fiber-v2/templates/fortune.qtpl similarity index 100% rename from frameworks/Go/fiber/src/templates/fortune.qtpl rename to frameworks/Go/fiber/fiber-v2/templates/fortune.qtpl diff --git a/frameworks/Go/fiber/src/templates/fortune.qtpl.go b/frameworks/Go/fiber/fiber-v2/templates/fortune.qtpl.go similarity index 100% rename from frameworks/Go/fiber/src/templates/fortune.qtpl.go rename to frameworks/Go/fiber/fiber-v2/templates/fortune.qtpl.go diff --git a/frameworks/Go/fiber/fiber-v3-prefork.dockerfile b/frameworks/Go/fiber/fiber-v3-prefork.dockerfile new file mode 100644 index 00000000000..142470bb3fa --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3-prefork.dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.25.6-alpine as builder + +WORKDIR /fiber + +COPY ./fiber-v3 /fiber + +RUN go mod download && \ + go install github.com/valyala/quicktemplate/qtc@latest && \ + qtc && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . + +FROM alpine:latest + +WORKDIR /fiber + +COPY --from=builder /fiber/app . + +EXPOSE 8080 + +CMD ./app -prefork diff --git a/frameworks/Go/fiber/fiber-v3/go.mod b/frameworks/Go/fiber/fiber-v3/go.mod new file mode 100644 index 00000000000..8f1eb000396 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/go.mod @@ -0,0 +1,38 @@ +module fiber-v3/app + +go 1.25.0 + +require ( + github.com/goccy/go-json v0.10.5 + github.com/gofiber/fiber/v3 v3.1.0 + github.com/jackc/pgx/v5 v5.8.0 + github.com/stretchr/testify v1.11.1 + github.com/valyala/quicktemplate v1.8.0 +) + +require ( + github.com/andybalholm/brotli v1.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gofiber/schema v1.7.0 // indirect + github.com/gofiber/utils/v2 v2.0.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/klauspost/compress v1.18.4 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/tinylib/msgp v1.6.3 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.69.0 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/net v0.50.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/frameworks/Go/fiber/fiber-v3/go.sum b/frameworks/Go/fiber/fiber-v3/go.sum new file mode 100644 index 00000000000..559d0e5c33f --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/go.sum @@ -0,0 +1,78 @@ +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gofiber/fiber/v3 v3.1.0 h1:1p4I820pIa+FGxfwWuQZ5rAyX0WlGZbGT6Hnuxt6hKY= +github.com/gofiber/fiber/v3 v3.1.0/go.mod h1:n2nYQovvL9z3Too/FGOfgtERjW3GQcAUqgfoezGBZdU= +github.com/gofiber/schema v1.7.0 h1:yNM+FNRZjyYEli9Ey0AXRBrAY9jTnb+kmGs3lJGPvKg= +github.com/gofiber/schema v1.7.0/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk= +github.com/gofiber/utils/v2 v2.0.2 h1:ShRRssz0F3AhTlAQcuEj54OEDtWF7+HJDwEi/aa6QLI= +github.com/gofiber/utils/v2 v2.0.2/go.mod h1:+9Ub4NqQ+IaJoTliq5LfdmOJAA/Hzwf4pXOxOa3RrJ0= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/shamaton/msgpack/v3 v3.1.0 h1:jsk0vEAqVvvS9+fTZ5/EcQ9tz860c9pWxJ4Iwecz8gU= +github.com/shamaton/msgpack/v3 v3.1.0/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= +github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= +github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= +github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= +github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/fiber/fiber-v3/server.go b/frameworks/Go/fiber/fiber-v3/server.go new file mode 100644 index 00000000000..958006ea78d --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/server.go @@ -0,0 +1,312 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "os" + "runtime" + "slices" + "sort" + "sync" + + "github.com/goccy/go-json" + "github.com/gofiber/fiber/v3" + + "fiber-v3/app/templates" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +var ( + db *pgxpool.Pool + cachedWorlds Worlds +) + +const ( + queryparam = "q" + helloworld = "Hello, World!" + worldcount = 10000 + worldselectsql = "SELECT id, randomNumber FROM World WHERE id = $1" + worldupdatesql = "UPDATE World SET randomNumber = $1 WHERE id = $2" + worldcachesql = "SELECT * FROM World LIMIT $1" + fortuneselectsql = "SELECT id, message FROM Fortune" + pathJSON = "/json" + pathDB = "/db" + pathQueries = "/queries" + pathCache = "/cached-worlds" + pathFortunes = "/fortunes" + pathUpdate = "/update" + pathText = "/plaintext" +) + +func main() { + initDatabase() + + config := fiber.Config{ + CaseSensitive: true, + StrictRouting: true, + DisableHeaderNormalizing: true, + ServerHeader: "go", + JSONEncoder: json.Marshal, + JSONDecoder: json.Unmarshal, + } + + app := fiber.New(config) + + app.Use(func(c fiber.Ctx) error { + switch c.Path() { + case pathJSON: + jsonHandler(c) + case pathDB: + dbHandler(c) + case pathQueries: + queriesHandler(c) + case pathCache: + cachedHandler(c) + case pathFortunes: + templateHandler(c) + case pathUpdate: + updateHandler(c) + case pathText: + plaintextHandler(c) + } + return nil + }) + + enablePrefork := slices.Contains(os.Args[1:], "-prefork") + log.Fatal(app.Listen(":8080", fiber.ListenConfig{ + DisableStartupMessage: true, + EnablePrefork: enablePrefork, + })) +} + +// Message ... +type Message struct { + Message string `json:"message"` +} + +// Worlds ... +type Worlds []World + +// World ... +type World struct { + ID int32 `json:"id"` + RandomNumber int32 `json:"randomNumber"` +} + +// JSONpool ... +var JSONpool = sync.Pool{ + New: func() interface{} { + return new(Message) + }, +} + +// AcquireJSON ... +func AcquireJSON() *Message { + return JSONpool.Get().(*Message) +} + +// ReleaseJSON ... +func ReleaseJSON(json *Message) { + json.Message = "" + JSONpool.Put(json) +} + +// WorldPool ... +var WorldPool = sync.Pool{ + New: func() interface{} { + return new(World) + }, +} + +// AcquireWorld ... +func AcquireWorld() *World { + return WorldPool.Get().(*World) +} + +// ReleaseWorld ... +func ReleaseWorld(w *World) { + w.ID = 0 + w.RandomNumber = 0 + WorldPool.Put(w) +} + +// WorldsPool ... +var WorldsPool = sync.Pool{ + New: func() interface{} { + return make(Worlds, 0, 500) + }, +} + +// AcquireWorlds ... +func AcquireWorlds() Worlds { + return WorldsPool.Get().(Worlds) +} + +// ReleaseWorlds ...ReleaseWorlds +func ReleaseWorlds(w Worlds) { + w = w[:0] + WorldsPool.Put(w) +} + +// initDatabase : +func initDatabase() { + maxConn := runtime.NumCPU() * 4 + if fiber.IsChild() { + maxConn = 5 + } + + var err error + db, err = pgxpool.New(context.Background(), + fmt.Sprintf( + "host=%s port=%d user=%s password=%s dbname=%s pool_max_conns=%d", + "tfb-database", 5432, + "benchmarkdbuser", + "benchmarkdbpass", + "hello_world", + maxConn, + )) + if err != nil { + panic(err) + } + populateCache() +} + +// this will populate the cached worlds for the cache test +func populateCache() { + worlds := make(Worlds, worldcount) + rows, err := db.Query(context.Background(), worldcachesql, worldcount) + if err != nil { + panic(err) + } + for i := 0; i < worldcount; i++ { + w := &worlds[i] + if !rows.Next() { + break + } + if err := rows.Scan(&w.ID, &w.RandomNumber); err != nil { + panic(err) + } + //db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + } + cachedWorlds = worlds +} + +// jsonHandler : +func jsonHandler(c fiber.Ctx) error { + m := AcquireJSON() + m.Message = helloworld + c.JSON(&m) + ReleaseJSON(m) + return nil +} + +// dbHandler : +func dbHandler(c fiber.Ctx) error { + w := AcquireWorld() + db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + c.JSON(&w) + ReleaseWorld(w) + return nil +} + +// Frameworks/Go/fasthttp/src/server-postgresql/server.go#104 +func templateHandler(c fiber.Ctx) error { + rows, _ := db.Query(context.Background(), fortuneselectsql) + + var f templates.Fortune + fortunes := make([]templates.Fortune, 0) + for rows.Next() { + _ = rows.Scan(&f.ID, &f.Message) + fortunes = append(fortunes, f) + } + rows.Close() + fortunes = append(fortunes, templates.Fortune{ + Message: "Additional fortune added at request time.", + }) + + sort.Slice(fortunes, func(i, j int) bool { + return fortunes[i].Message < fortunes[j].Message + }) + + c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8) + + templates.WriteFortunePage(c.RequestCtx(), fortunes) + return nil +} + +// queriesHandler : +func queriesHandler(c fiber.Ctx) error { + n := QueriesCount(c) + worlds := AcquireWorlds()[:n] + for i := 0; i < n; i++ { + w := &worlds[i] + db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + } + c.JSON(&worlds) + ReleaseWorlds(worlds) + return nil +} + +// updateHandler : +func updateHandler(c fiber.Ctx) error { + n := QueriesCount(c) + worlds := AcquireWorlds()[:n] + for i := 0; i < n; i++ { + w := &worlds[i] + db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) + w.RandomNumber = int32(RandomWorld()) + } + // sorting is required for insert deadlock prevention. + sort.Slice(worlds, func(i, j int) bool { + return worlds[i].ID < worlds[j].ID + }) + + batch := pgx.Batch{} + for _, w := range worlds { + batch.Queue(worldupdatesql, w.RandomNumber, w.ID) + } + db.SendBatch(context.Background(), &batch).Close() + c.JSON(&worlds) + ReleaseWorlds(worlds) + + return nil +} + +var helloworldRaw = []byte("Hello, World!") + +// plaintextHandler : +func plaintextHandler(c fiber.Ctx) error { + return c.Send(helloworldRaw) +} + +// cachedHandler : +func cachedHandler(c fiber.Ctx) error { + n := QueriesCount(c) + worlds := AcquireWorlds()[:n] + for i := 0; i < n; i++ { + worlds[i] = cachedWorlds[RandomWorld()-1] + } + c.JSON(&worlds) + ReleaseWorlds(worlds) + return nil +} + +// RandomWorld : +func RandomWorld() int { + return rand.Intn(worldcount) + 1 +} + +// QueriesCount : +func QueriesCount(c fiber.Ctx) int { + n := c.Request().URI().QueryArgs().GetUintOrZero(queryparam) + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + return n +} diff --git a/frameworks/Go/fiber/fiber-v3/server_test.go b/frameworks/Go/fiber/fiber-v3/server_test.go new file mode 100644 index 00000000000..ae1df74b387 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/server_test.go @@ -0,0 +1,69 @@ +package main + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/goccy/go-json" + "github.com/gofiber/fiber/v3" +) + +// go test -v -run=^$ -bench=Benchmark_Plaintext -benchmem -count=4 +func Benchmark_Plaintext(b *testing.B) { + app := fiber.New(fiber.Config{ + JSONEncoder: json.Marshal, + JSONDecoder: json.Unmarshal, + }) + + app.Get("/plaintext", plaintextHandler) + + var ( + resp *http.Response + err error + ) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + resp, err = app.Test(httptest.NewRequest("GET", "/plaintext", nil)) + } + + assert.Equal(b, nil, err, "app.Test(req)") + assert.Equal(b, 200, resp.StatusCode, "Status code") + assert.Equal(b, fiber.MIMETextPlainCharsetUTF8, resp.Header.Get("Content-Type")) + body, _ := io.ReadAll(resp.Body) + assert.Equal(b, helloworldRaw, body) +} + +// go test -v -run=^$ -bench=Benchmark_JSON -benchmem -count=4 +func Benchmark_JSON(b *testing.B) { + app := fiber.New(fiber.Config{ + JSONEncoder: json.Marshal, + JSONDecoder: json.Unmarshal, + }) + + app.Get("/json", jsonHandler) + + var ( + resp *http.Response + err error + ) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + resp, err = app.Test(httptest.NewRequest("GET", "/json", nil)) + } + + assert.Equal(b, nil, err, "app.Test(req)") + assert.Equal(b, 200, resp.StatusCode, "Status code") + assert.Equal(b, fiber.MIMEApplicationJSON, resp.Header.Get("Content-Type")) + body, _ := io.ReadAll(resp.Body) + assert.Equal(b, `{"message":"Hello, World!"}`, string(body)) +} diff --git a/frameworks/Go/fiber/fiber-v3/templates/fortune.go b/frameworks/Go/fiber/fiber-v3/templates/fortune.go new file mode 100644 index 00000000000..1d41ca2c80d --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/templates/fortune.go @@ -0,0 +1,53 @@ +package templates + +import ( + "sync" +) + +type Fortune struct { + ID int `json:"id,omitempty"` + Message string `json:"message,omitempty"` +} + +type Fortunes struct { + F []Fortune +} + +//go:generate go run github.com/valyala/quicktemplate/qtc + +var fortunePool = &sync.Pool{ + New: func() interface{} { + return new(Fortune) + }, +} + +var fortunesPool = &sync.Pool{ + New: func() interface{} { + return &Fortunes{ + F: make([]Fortune, 0), + } + }, +} + +// AcquireFortune returns new message from pool. +func AcquireFortune() *Fortune { + return fortunePool.Get().(*Fortune) +} + +// ReleaseFortune resets the message and return it to the pool. +func ReleaseFortune(f *Fortune) { + f.ID = 0 + f.Message = "" + fortunePool.Put(f) +} + +// AcquireFortunes returns new fortunes from pool. +func AcquireFortunes() *Fortunes { + return fortunesPool.Get().(*Fortunes) +} + +// ReleaseFortunes resets the fortunes and return it to the pool. +func ReleaseFortunes(f *Fortunes) { + f.F = f.F[:0] + fortunesPool.Put(f) +} diff --git a/frameworks/Go/fiber/fiber-v3/templates/fortune.qtpl b/frameworks/Go/fiber/fiber-v3/templates/fortune.qtpl new file mode 100644 index 00000000000..d387990d4ae --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/templates/fortune.qtpl @@ -0,0 +1,15 @@ +{% func FortunePage(rows []Fortune) %} + + +Fortunes + + + + +{% for _, r := range rows %} + +{% endfor %} +
idmessage
{%d int(r.ID) %}{%s r.Message %}
+ + +{% endfunc %} diff --git a/frameworks/Go/fiber/fiber-v3/templates/fortune.qtpl.go b/frameworks/Go/fiber/fiber-v3/templates/fortune.qtpl.go new file mode 100644 index 00000000000..8af0bbf4f10 --- /dev/null +++ b/frameworks/Go/fiber/fiber-v3/templates/fortune.qtpl.go @@ -0,0 +1,81 @@ +// Code generated by qtc from "fortune.qtpl". DO NOT EDIT. +// See https://github.com/valyala/quicktemplate for details. + +//line fortune.qtpl:1 +package templates + +//line fortune.qtpl:1 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line fortune.qtpl:1 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line fortune.qtpl:1 +func StreamFortunePage(qw422016 *qt422016.Writer, rows []Fortune) { +//line fortune.qtpl:1 + qw422016.N().S(` + + +Fortunes + + + + +`) +//line fortune.qtpl:9 + for _, r := range rows { +//line fortune.qtpl:9 + qw422016.N().S(` + +`) +//line fortune.qtpl:11 + } +//line fortune.qtpl:11 + qw422016.N().S(` +
idmessage
`) +//line fortune.qtpl:10 + qw422016.N().D(int(r.ID)) +//line fortune.qtpl:10 + qw422016.N().S(``) +//line fortune.qtpl:10 + qw422016.E().S(r.Message) +//line fortune.qtpl:10 + qw422016.N().S(`
+ + +`) +//line fortune.qtpl:15 +} + +//line fortune.qtpl:15 +func WriteFortunePage(qq422016 qtio422016.Writer, rows []Fortune) { +//line fortune.qtpl:15 + qw422016 := qt422016.AcquireWriter(qq422016) +//line fortune.qtpl:15 + StreamFortunePage(qw422016, rows) +//line fortune.qtpl:15 + qt422016.ReleaseWriter(qw422016) +//line fortune.qtpl:15 +} + +//line fortune.qtpl:15 +func FortunePage(rows []Fortune) string { +//line fortune.qtpl:15 + qb422016 := qt422016.AcquireByteBuffer() +//line fortune.qtpl:15 + WriteFortunePage(qb422016, rows) +//line fortune.qtpl:15 + qs422016 := string(qb422016.B) +//line fortune.qtpl:15 + qt422016.ReleaseByteBuffer(qb422016) +//line fortune.qtpl:15 + return qs422016 +//line fortune.qtpl:15 +} diff --git a/frameworks/Go/fiber/fiber.dockerfile b/frameworks/Go/fiber/fiber.dockerfile index fc82a07891c..402025c8c01 100644 --- a/frameworks/Go/fiber/fiber.dockerfile +++ b/frameworks/Go/fiber/fiber.dockerfile @@ -1,11 +1,12 @@ -FROM golang:1.24.2-alpine as builder +FROM golang:1.25.6-alpine as builder WORKDIR /fiber -COPY ./src /fiber +COPY ./fiber-v3 /fiber RUN go mod download && \ - go generate -x ./templates && \ + go install github.com/valyala/quicktemplate/qtc@latest && \ + qtc && \ GOAMD64=v3 go build -ldflags="-s -w" -o app . FROM alpine:latest diff --git a/frameworks/Go/fiber/src/go.mod b/frameworks/Go/fiber/src/go.mod deleted file mode 100644 index 6e1dcc6247f..00000000000 --- a/frameworks/Go/fiber/src/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module fiber/app - -go 1.24.0 - -toolchain go1.24.1 - -require ( - github.com/goccy/go-json v0.10.5 - github.com/gofiber/fiber/v2 v2.52.9 - github.com/jackc/pgx/v5 v5.7.4 - github.com/valyala/quicktemplate v1.8.0 -) - -require ( - github.com/andybalholm/brotli v1.1.1 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/puddle/v2 v2.2.2 // indirect - github.com/klauspost/compress v1.18.0 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.60.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect -) diff --git a/frameworks/Go/fiber/src/go.sum b/frameworks/Go/fiber/src/go.sum deleted file mode 100644 index bbb70d60f3f..00000000000 --- a/frameworks/Go/fiber/src/go.sum +++ /dev/null @@ -1,58 +0,0 @@ -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw= -github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= -github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= -github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= -github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw= -github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc= -github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= -github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= -github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= -github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/fiber/src/server.go b/frameworks/Go/fiber/src/server.go deleted file mode 100644 index c592ccd3170..00000000000 --- a/frameworks/Go/fiber/src/server.go +++ /dev/null @@ -1,313 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "math/rand" - "os" - "runtime" - "sort" - "sync" - - "github.com/goccy/go-json" - "github.com/gofiber/fiber/v2" - - "fiber/app/templates" - - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgxpool" -) - -var ( - db *pgxpool.Pool - cachedWorlds Worlds -) - -const ( - queryparam = "q" - helloworld = "Hello, World!" - worldcount = 10000 - worldselectsql = "SELECT id, randomNumber FROM World WHERE id = $1" - worldupdatesql = "UPDATE World SET randomNumber = $1 WHERE id = $2" - worldcachesql = "SELECT * FROM World LIMIT $1" - fortuneselectsql = "SELECT id, message FROM Fortune" - pathJSON = "/json" - pathDB = "/db" - pathQueries = "/queries" - pathCache = "/cached-worlds" - pathFortunes = "/fortunes" - pathUpdate = "/update" - pathText = "/plaintext" -) - -func main() { - initDatabase() - - config := fiber.Config{ - CaseSensitive: true, - StrictRouting: true, - DisableHeaderNormalizing: true, - ServerHeader: "go", - JSONEncoder: json.Marshal, - JSONDecoder: json.Unmarshal, - } - - for i := range os.Args[1:] { - if os.Args[1:][i] == "-prefork" { - config.Prefork = true - } - } - - app := fiber.New(config) - - app.Use(func(c *fiber.Ctx) error { - switch c.Path() { - case pathJSON: - jsonHandler(c) - case pathDB: - dbHandler(c) - case pathQueries: - queriesHandler(c) - case pathCache: - cachedHandler(c) - case pathFortunes: - templateHandler(c) - case pathUpdate: - updateHandler(c) - case pathText: - plaintextHandler(c) - } - return nil - }) - - log.Fatal(app.Listen(":8080")) -} - -// Message ... -type Message struct { - Message string `json:"message"` -} - -// Worlds ... -type Worlds []World - -// World ... -type World struct { - ID int32 `json:"id"` - RandomNumber int32 `json:"randomNumber"` -} - -// JSONpool ... -var JSONpool = sync.Pool{ - New: func() interface{} { - return new(Message) - }, -} - -// AcquireJSON ... -func AcquireJSON() *Message { - return JSONpool.Get().(*Message) -} - -// ReleaseJSON ... -func ReleaseJSON(json *Message) { - json.Message = "" - JSONpool.Put(json) -} - -// WorldPool ... -var WorldPool = sync.Pool{ - New: func() interface{} { - return new(World) - }, -} - -// AcquireWorld ... -func AcquireWorld() *World { - return WorldPool.Get().(*World) -} - -// ReleaseWorld ... -func ReleaseWorld(w *World) { - w.ID = 0 - w.RandomNumber = 0 - WorldPool.Put(w) -} - -// WorldsPool ... -var WorldsPool = sync.Pool{ - New: func() interface{} { - return make(Worlds, 0, 500) - }, -} - -// AcquireWorlds ... -func AcquireWorlds() Worlds { - return WorldsPool.Get().(Worlds) -} - -// ReleaseWorlds ...ReleaseWorlds -func ReleaseWorlds(w Worlds) { - w = w[:0] - WorldsPool.Put(w) -} - -// initDatabase : -func initDatabase() { - maxConn := runtime.NumCPU() * 4 - if fiber.IsChild() { - maxConn = 5 - } - - var err error - db, err = pgxpool.New(context.Background(), - fmt.Sprintf( - "host=%s port=%d user=%s password=%s dbname=%s pool_max_conns=%d", - "tfb-database", 5432, - "benchmarkdbuser", - "benchmarkdbpass", - "hello_world", - maxConn, - )) - if err != nil { - panic(err) - } - populateCache() -} - -// this will populate the cached worlds for the cache test -func populateCache() { - worlds := make(Worlds, worldcount) - rows, err := db.Query(context.Background(), worldcachesql, worldcount) - if err != nil { - panic(err) - } - for i := 0; i < worldcount; i++ { - w := &worlds[i] - if !rows.Next() { - break - } - if err := rows.Scan(&w.ID, &w.RandomNumber); err != nil { - panic(err) - } - //db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) - } - cachedWorlds = worlds -} - -// jsonHandler : -func jsonHandler(c *fiber.Ctx) error { - m := AcquireJSON() - m.Message = helloworld - c.JSON(&m) - ReleaseJSON(m) - return nil -} - -// dbHandler : -func dbHandler(c *fiber.Ctx) error { - w := AcquireWorld() - db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) - c.JSON(&w) - ReleaseWorld(w) - return nil -} - -// Frameworks/Go/fasthttp/src/server-postgresql/server.go#104 -func templateHandler(c *fiber.Ctx) error { - rows, _ := db.Query(context.Background(), fortuneselectsql) - - var f templates.Fortune - fortunes := make([]templates.Fortune, 0) - for rows.Next() { - _ = rows.Scan(&f.ID, &f.Message) - fortunes = append(fortunes, f) - } - rows.Close() - fortunes = append(fortunes, templates.Fortune{ - Message: "Additional fortune added at request time.", - }) - - sort.Slice(fortunes, func(i, j int) bool { - return fortunes[i].Message < fortunes[j].Message - }) - - c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8) - - templates.WriteFortunePage(c.Context(), fortunes) - return nil -} - -// queriesHandler : -func queriesHandler(c *fiber.Ctx) error { - n := QueriesCount(c) - worlds := AcquireWorlds()[:n] - for i := 0; i < n; i++ { - w := &worlds[i] - db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) - } - c.JSON(&worlds) - ReleaseWorlds(worlds) - return nil -} - -// updateHandler : -func updateHandler(c *fiber.Ctx) error { - n := QueriesCount(c) - worlds := AcquireWorlds()[:n] - for i := 0; i < n; i++ { - w := &worlds[i] - db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) - w.RandomNumber = int32(RandomWorld()) - } - // sorting is required for insert deadlock prevention. - sort.Slice(worlds, func(i, j int) bool { - return worlds[i].ID < worlds[j].ID - }) - - batch := pgx.Batch{} - for _, w := range worlds { - batch.Queue(worldupdatesql, w.RandomNumber, w.ID) - } - db.SendBatch(context.Background(), &batch).Close() - c.JSON(&worlds) - ReleaseWorlds(worlds) - - return nil -} - -var helloworldRaw = []byte("Hello, World!") - -// plaintextHandler : -func plaintextHandler(c *fiber.Ctx) error { - return c.Send(helloworldRaw) -} - -// cachedHandler : -func cachedHandler(c *fiber.Ctx) error { - n := QueriesCount(c) - worlds := AcquireWorlds()[:n] - for i := 0; i < n; i++ { - worlds[i] = cachedWorlds[RandomWorld()-1] - } - c.JSON(&worlds) - ReleaseWorlds(worlds) - return nil -} - -// RandomWorld : -func RandomWorld() int { - return rand.Intn(worldcount) + 1 -} - -// QueriesCount : -func QueriesCount(c *fiber.Ctx) int { - n := c.Request().URI().QueryArgs().GetUintOrZero(queryparam) - if n < 1 { - n = 1 - } else if n > 500 { - n = 500 - } - return n -} diff --git a/frameworks/Go/gnet/benchmark_config.json b/frameworks/Go/gnet/benchmark_config.json index 1ff8439be6d..aca33ee3723 100644 --- a/frameworks/Go/gnet/benchmark_config.json +++ b/frameworks/Go/gnet/benchmark_config.json @@ -4,7 +4,7 @@ "default": { "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "None", "framework": "gnet", diff --git a/frameworks/Go/goframe/src/go.mod b/frameworks/Go/goframe/src/go.mod index ee265ecc7d0..d26a04f3ec8 100644 --- a/frameworks/Go/goframe/src/go.mod +++ b/frameworks/Go/goframe/src/go.mod @@ -1,6 +1,6 @@ module goframe/app -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -14,12 +14,13 @@ require ( require ( github.com/BurntSushi/toml v1.5.0 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect @@ -41,15 +42,15 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/sdk v1.35.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect golang.org/x/arch v0.15.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/net v0.38.0 // indirect - golang.org/x/sys v0.31.0 // indirect + golang.org/x/sys v0.40.0 // indirect golang.org/x/text v0.23.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/frameworks/Go/goframe/src/go.sum b/frameworks/Go/goframe/src/go.sum index 50336211cdc..0a8d9161f0b 100644 --- a/frameworks/Go/goframe/src/go.sum +++ b/frameworks/Go/goframe/src/go.sum @@ -7,6 +7,8 @@ github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= @@ -29,8 +31,8 @@ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -143,8 +145,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -167,8 +169,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -177,16 +179,18 @@ github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdq github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -253,8 +257,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/frameworks/Go/goravel/src/fiber/go.mod b/frameworks/Go/goravel/src/fiber/go.mod index e0ee741ee37..5623cf69bb1 100644 --- a/frameworks/Go/goravel/src/fiber/go.mod +++ b/frameworks/Go/goravel/src/fiber/go.mod @@ -20,7 +20,7 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/pubsub v1.36.1 // indirect - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.1.1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest/adal v0.9.16 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect @@ -63,10 +63,10 @@ require ( github.com/go-redsync/redsync/v4 v4.8.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-stack/stack v1.8.0 // indirect - github.com/gofiber/fiber/v2 v2.52.9 // indirect + github.com/gofiber/fiber/v2 v2.52.12 // indirect github.com/gofiber/template v1.8.3 // indirect github.com/gofiber/template/html/v2 v2.1.1 // indirect - github.com/gofiber/utils v1.1.0 // indirect + github.com/gofiber/utils v1.2.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang-migrate/migrate/v4 v4.17.1 // indirect diff --git a/frameworks/Go/goravel/src/fiber/go.sum b/frameworks/Go/goravel/src/fiber/go.sum index 5e100bb5998..c7a9e50b60b 100644 --- a/frameworks/Go/goravel/src/fiber/go.sum +++ b/frameworks/Go/goravel/src/fiber/go.sum @@ -55,8 +55,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= +filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= @@ -273,14 +273,14 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw= -github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= github.com/gofiber/template/html/v2 v2.1.1 h1:QEy3O3EBkvwDthy5bXVGUseOyO6ldJoiDxlF4+MJiV8= github.com/gofiber/template/html/v2 v2.1.1/go.mod h1:2G0GHHOUx70C1LDncoBpe4T6maQbNa4x1CVNFW0wju0= -github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= -github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= +github.com/gofiber/utils v1.2.0 h1:NCaqd+Efg3khhN++eeUUTyBz+byIxAsmIjpl8kKOMIc= +github.com/gofiber/utils v1.2.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= diff --git a/frameworks/Go/revel/README.md b/frameworks/Go/revel/README.md deleted file mode 100644 index 95553f9f225..00000000000 --- a/frameworks/Go/revel/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Revel Benchmarking Test - -A high productivity, full-stack web framework for the Go language. - -Community : [gitter](https://gitter.im/revel/community) -Source : [github](https://github.com/revel) -Help : [http://revel.github.io/](http://revel.github.io/) - diff --git a/frameworks/Go/revel/benchmark_config.json b/frameworks/Go/revel/benchmark_config.json deleted file mode 100644 index c2ca8e72d4a..00000000000 --- a/frameworks/Go/revel/benchmark_config.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "framework": "revel", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "revel", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Revel", - "notes": "", - "versus": "go", - "tags": ["broken"] - }, - "fast": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "revel", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Revel", - "notes": "", - "versus": "go", - "tags": ["broken"] - }, - "raw": { - "db_url": "/db", - "query_url": "/db?queries=", - "fortune_url": "/fortune", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "revel", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Revel-raw", - "notes": "", - "versus": "go", - "tags": ["broken"] - }, - "jet": { - "db_url": "/jet-db", - "query_url": "/jet-db?queries=", - "fortune_url": "/jet-fortune", - "update_url": "/jet-update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "revel", - "language": "Go", - "flavor": "None", - "orm": "micro", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Revel-jet", - "notes": "", - "versus": "go", - "tags": ["broken"] - }, - "qbs": { - "db_url": "/qbs-db", - "query_url": "/qbs-db?queries=", - "fortune_url": "/qbs-fortune", - "update_url": "/qbs-update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "revel", - "language": "Go", - "flavor": "None", - "orm": "micro", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Revel-qbs", - "notes": "", - "versus": "go", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Go/revel/config.toml b/frameworks/Go/revel/config.toml deleted file mode 100644 index 00318eb0342..00000000000 --- a/frameworks/Go/revel/config.toml +++ /dev/null @@ -1,73 +0,0 @@ -[framework] -name = "revel" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" - -[raw] -urls.db = "/db" -urls.query = "/db?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortune" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" - -[qbs] -urls.db = "/qbs-db" -urls.query = "/qbs-db?queries=" -urls.update = "/qbs-update?queries=" -urls.fortune = "/qbs-fortune" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "micro" -platform = "None" -webserver = "None" -versus = "go" - -[jet] -urls.db = "/jet-db" -urls.query = "/jet-db?queries=" -urls.update = "/jet-update?queries=" -urls.fortune = "/jet-fortune" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "micro" -platform = "None" -webserver = "None" -versus = "go" - -[fast] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" diff --git a/frameworks/Go/revel/revel-fast.dockerfile b/frameworks/Go/revel/revel-fast.dockerfile deleted file mode 100644 index 57ae4455eda..00000000000 --- a/frameworks/Go/revel/revel-fast.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM golang:1.24.2 - -ADD ./ /revel -WORKDIR /revel - -ENV GOPATH /revel -ENV PATH ${GOPATH}/bin:${PATH} - -RUN go get -u github.com/revel/cmd/revel -RUN revel build -a benchmark -t target -m prod-fasthttp -v - -EXPOSE 8080 - -CMD target/run.sh diff --git a/frameworks/Go/revel/revel-jet.dockerfile b/frameworks/Go/revel/revel-jet.dockerfile deleted file mode 100644 index e33c0464efb..00000000000 --- a/frameworks/Go/revel/revel-jet.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM golang:1.24.2 - -ADD ./ /revel -WORKDIR /revel - -ENV GOPATH /revel -ENV PATH ${GOPATH}/bin:${PATH} - -RUN go get -u github.com/revel/cmd/revel -RUN revel build -a benchmark -t target -m prod -v - -EXPOSE 8080 - -CMD target/run.sh - diff --git a/frameworks/Go/revel/revel-qbs.dockerfile b/frameworks/Go/revel/revel-qbs.dockerfile deleted file mode 100644 index 8252703fb1a..00000000000 --- a/frameworks/Go/revel/revel-qbs.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM golang:1.24.2 - -ADD ./ /revel -WORKDIR /revel - -ENV GOPATH /revel -ENV PATH ${GOPATH}/bin:${PATH} - - -RUN go get -u github.com/revel/cmd/revel -RUN revel build -a benchmark -t target -m prod -v - -EXPOSE 8080 - -CMD target/run.sh - diff --git a/frameworks/Go/revel/revel-raw.dockerfile b/frameworks/Go/revel/revel-raw.dockerfile deleted file mode 100644 index 1f10775f1bc..00000000000 --- a/frameworks/Go/revel/revel-raw.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM golang:1.24.2 - -ADD ./ /revel -WORKDIR /revel - -ENV GOPATH /revel -ENV PATH ${GOPATH}/bin:${PATH} - -RUN go get github.com/revel/cmd/revel -RUN revel build -a benchmark -t target -m prod -v - -EXPOSE 8080 - -CMD target/run.sh diff --git a/frameworks/Go/revel/revel.dockerfile b/frameworks/Go/revel/revel.dockerfile deleted file mode 100644 index 9956c4e0d76..00000000000 --- a/frameworks/Go/revel/revel.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM golang:1.24.2 - -ADD ./ /revel -WORKDIR /revel - -ENV GOPATH /revel -ENV PATH ${GOPATH}/bin:${PATH} - -RUN go get -u github.com/revel/cmd/revel -RUN revel build -a benchmark -t target -m prod -v - -EXPOSE 8080 - -CMD target/run.sh diff --git a/frameworks/Go/revel/src/benchmark/app/controllers/app.go b/frameworks/Go/revel/src/benchmark/app/controllers/app.go deleted file mode 100644 index 2a993e5fec2..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/controllers/app.go +++ /dev/null @@ -1,161 +0,0 @@ -package controllers - -import ( - "database/sql" - "math/rand" - "sort" - - dbm "benchmark/app/db" - - "github.com/revel/revel" -) - -type MessageStruct struct { - Message string `json:"message"` -} - -type World struct { - Id uint16 `json:"id" qbs:"pk"` - RandomNumber uint16 `json:"randomNumber"` -} - -type Fortune struct { - Id uint16 `json:"id" qbs:"pk"` - Message string `json:"message"` -} - -const ( - WorldSelect = "SELECT id,randomNumber FROM World where id=?" - FortuneSelect = "SELECT id,message FROM Fortune" - WorldUpdate = "UPDATE World SET randomNumber = ? where id = ?" - WorldRowCount = 10000 - MaxConnectionCount = 256 -) - -var ( - worldStatement *sql.Stmt - fortuneStatement *sql.Stmt - updateStatement *sql.Stmt -) - -func init() { - revel.Filters = []revel.Filter{ - ServerHeaderFilter, - revel.RouterFilter, - revel.ParamsFilter, - revel.ActionInvoker, - } - revel.OnAppStart(func() { - var err error - db.Init() - db.Db.SetMaxIdleConns(MaxConnectionCount) - dbm.InitJet() - dbm.Jet.SetMaxIdleConns(MaxConnectionCount) - dbm.InitQbs(MaxConnectionCount) - - if worldStatement, err = db.Db.Prepare(WorldSelect); err != nil { - revel.ERROR.Fatalln(err) - } - if fortuneStatement, err = db.Db.Prepare(FortuneSelect); err != nil { - revel.ERROR.Fatalln(err) - } - if updateStatement, err = db.Db.Prepare(WorldUpdate); err != nil { - revel.ERROR.Fatalln(err) - } - }) -} - -var ServerHeaderFilter = func(c *revel.Controller, fc []revel.Filter) { - c.Response.Out.Header().Set("Server", "revel") - fc[0](c, fc[1:]) // Execute the next filter stage. -} - -type App struct { - *revel.Controller -} - -func (c App) Json() revel.Result { - return c.RenderJSON(MessageStruct{"Hello, World!"}) -} - -func (c App) Plaintext() revel.Result { - return c.RenderText("Hello, World!") -} - -func (c App) Db(queries int) revel.Result { - _, foundQuery := c.Params.Values["queries"] - if queries > 500 { - queries = 500 - } - if queries == 0 { - queries = 1 - } - ww := make([]World, queries) - for i := 0; i < queries; i++ { - err := worldStatement.QueryRow(rand.Intn(WorldRowCount)+1). - Scan(&ww[i].Id, &ww[i].RandomNumber) - if err != nil { - c.Log.Fatalf("Error scanning world row: %v", err) - } - } - if !foundQuery { - return c.RenderJSON(ww[0]) - } - return c.RenderJSON(ww) -} - -func (c App) Update(queries int) revel.Result { - _, foundQuery := c.Params.Values["queries"] - if queries > 500 { - queries = 500 - } else if queries == 0 { - queries = 1 - } - ww := make([]World, queries) - for i := 0; i < queries; i++ { - err := worldStatement.QueryRow(rand.Intn(WorldRowCount)+1). - Scan(&ww[i].Id, &ww[i].RandomNumber) - if err != nil { - revel.ERROR.Fatalf("Error scanning world row: %v", err) - } - ww[i].RandomNumber = uint16(rand.Intn(WorldRowCount) + 1) - updateStatement.Exec(ww[i].RandomNumber, ww[i].Id) - } - if !foundQuery { - return c.RenderJSON(ww[0]) - } - return c.RenderJSON(ww) -} - -func (c App) Fortune() revel.Result { - fortunes := make([]*Fortune, 0) - - rows, err := fortuneStatement.Query() - if err != nil { - revel.ERROR.Fatalf("Error preparing statement: %v", err) - } - - i := 0 - var fortune *Fortune - for rows.Next() { - fortune = new(Fortune) - if err = rows.Scan(&fortune.Id, &fortune.Message); err != nil { - revel.ERROR.Fatalf("Error scanning fortune row: %v", err) - } - fortunes = append(fortunes, fortune) - i++ - } - fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."}) - - sort.Sort(ByMessage{fortunes}) - return c.Render(fortunes) -} - -type Fortunes []*Fortune - -func (s Fortunes) Len() int { return len(s) } -func (s Fortunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -type ByMessage struct{ Fortunes } - -func (s ByMessage) Less(i, j int) bool { return s.Fortunes[i].Message < s.Fortunes[j].Message } diff --git a/frameworks/Go/revel/src/benchmark/app/controllers/jet.go b/frameworks/Go/revel/src/benchmark/app/controllers/jet.go deleted file mode 100644 index 5225e012a15..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/controllers/jet.go +++ /dev/null @@ -1,70 +0,0 @@ -package controllers - -import ( - "math/rand" - "sort" - - "benchmark/app/db" - - "github.com/revel/revel" -) - -func (c App) JetDb(queries int) revel.Result { - _, foundQuery := c.Params.Values["queries"] - if queries>500 { - queries = 500 - } - if queries == 0 { - queries = 1 - } - - ww := make([]World, queries) - for i := 0; i < queries; i++ { - err := db.Jet.Query(WorldSelect, rand.Intn(WorldRowCount)+1).Rows(&ww[i]) - if err != nil { - revel.ERROR.Fatalf("Db/WorldSelect2 error: %v", err) - } - } - if !foundQuery { - return c.RenderJSON(ww[0]) - } - return c.RenderJSON(ww) -} - -func (c App) JetUpdate(queries int) revel.Result { - _, foundQuery := c.Params.Values["queries"] - if queries>500 { - queries = 500 - } - if queries == 0 { - queries = 1 - } - - ww := make([]World, queries) - for i := 0; i < queries; i++ { - err := db.Jet.Query(WorldSelect, rand.Intn(WorldRowCount)+1).Rows(&ww[i]) - if err != nil { - revel.ERROR.Fatalf("Error scanning world row: %v", err) - } - ww[i].RandomNumber = uint16(rand.Intn(WorldRowCount) + 1) - if err = db.Jet.Query(WorldUpdate, ww[i].RandomNumber, ww[i].Id).Run(); err != nil { - revel.ERROR.Fatalf("Update/WorldUpdate2 error: %v", err) - } - } - if !foundQuery { - return c.RenderJSON(ww[0]) - } - return c.RenderJSON(ww) -} - -func (c App) JetFortune() revel.Result { - var fortunes Fortunes - err := db.Jet.Query(FortuneSelect).Rows(&fortunes) - if err != nil { - revel.ERROR.Fatalf("Fortune/FortuneSelect error: %v", err) - } - fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."}) - sort.Sort(ByMessage{fortunes}) - c.ViewArgs["fortunes"] = fortunes - return c.RenderTemplate("App/Fortune.html") -} diff --git a/frameworks/Go/revel/src/benchmark/app/controllers/qbs.go b/frameworks/Go/revel/src/benchmark/app/controllers/qbs.go deleted file mode 100644 index e2555451f8a..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/controllers/qbs.go +++ /dev/null @@ -1,74 +0,0 @@ -package controllers - -import ( - "math/rand" - "sort" - - "github.com/coocood/qbs" - "github.com/revel/revel" -) - -func (c App) QbsDb(queries int) revel.Result { - qbs, _ := qbs.GetQbs() - defer qbs.Close() - _, foundQuery := c.Params.Values["queries"] - if queries>500 { - queries = 500 - } - if queries == 0 { - queries = 1 - } - - ww := make([]World, queries) - for i := 0; i < queries; i++ { - ww[i].Id = uint16(rand.Intn(WorldRowCount) + 1) - if err := qbs.Find(&ww[i]); err != nil { - revel.ERROR.Fatalf("Error scanning world row: %v", err) - } - } - if !foundQuery { - return c.RenderJSON(ww[0]) - } - return c.RenderJSON(ww) -} - -func (c App) QbsUpdate(queries int) revel.Result { - qbs, _ := qbs.GetQbs() - defer qbs.Close() - _, foundQuery := c.Params.Values["queries"] - if queries>500 { - queries = 500 - } - if queries == 0 { - queries = 1 - } - - ww := make([]World, queries) - for i := 0; i < queries; i++ { - ww[i].Id = uint16(rand.Intn(WorldRowCount) + 1) - if err := qbs.Find(&ww[i]); err != nil { - revel.ERROR.Fatalf("Error scanning world row: %v", err) - } - ww[i].RandomNumber = uint16(rand.Intn(WorldRowCount) + 1) - if _, err := qbs.Save(&ww[i]); err != nil { - revel.ERROR.Fatalf("Error scanning world row: %v", err) - } - } - if !foundQuery { - return c.RenderJSON(ww[0]) - } - return c.RenderJSON(ww) -} - -func (c App) QbsFortune() revel.Result { - qbs, _ := qbs.GetQbs() - defer qbs.Close() - - var fortunes []*Fortune - qbs.FindAll(&fortunes) - fortunes = append(fortunes, - &Fortune{Message: "Additional fortune added at request time."}) - sort.Sort(ByMessage{fortunes}) - c.ViewArgs["fortunes"] = fortunes - return c.RenderTemplate("App/Fortune.html") -} diff --git a/frameworks/Go/revel/src/benchmark/app/db/jet.go b/frameworks/Go/revel/src/benchmark/app/db/jet.go deleted file mode 100644 index 019332c2d34..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/db/jet.go +++ /dev/null @@ -1,30 +0,0 @@ -package db - -import ( - "github.com/eaigner/jet" - "github.com/revel/revel" -) - -var ( - Jet *jet.Db -) - -func InitJet() { - // Read configuration. - var found bool - var driver, spec string - if driver, found = revel.Config.String("db.driver"); !found { - revel.ERROR.Fatal("No db.driver found.") - } - if spec, found = revel.Config.String("db.spec"); !found { - revel.ERROR.Fatal("No db.spec found.") - } - - // Open a connection. - var err error - Jet, err = jet.Open(driver, spec) - if err != nil { - revel.ERROR.Fatal(err) - } - // Jet.SetLogger(jet.NewLogger(os.Stdout)) -} diff --git a/frameworks/Go/revel/src/benchmark/app/db/qbs.go b/frameworks/Go/revel/src/benchmark/app/db/qbs.go deleted file mode 100644 index e1b1bb76017..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/db/qbs.go +++ /dev/null @@ -1,30 +0,0 @@ -package db - -import ( - "github.com/coocood/qbs" - "github.com/revel/revel" -) - -func InitQbs(maxConn int) { - var ( - found bool - driver, spec string - ) - if driver, found = revel.Config.String("db.driver"); !found { - revel.ERROR.Fatal("No db.driver found.") - } - if spec, found = revel.Config.String("db.spec"); !found { - revel.ERROR.Fatal("No db.spec found.") - } - - // QBS uses snake case by default; override the name convention. - qbs.ColumnNameToFieldName = noConvert - qbs.FieldNameToColumnName = noConvert - qbs.TableNameToStructName = noConvert - qbs.StructNameToTableName = noConvert - - qbs.Register(driver, spec, "", qbs.NewMysql()) - qbs.ChangePoolSize(maxConn) -} - -func noConvert(s string) string { return s } diff --git a/frameworks/Go/revel/src/benchmark/app/views/App/Fortune.html b/frameworks/Go/revel/src/benchmark/app/views/App/Fortune.html deleted file mode 100644 index 19e34867c73..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/views/App/Fortune.html +++ /dev/null @@ -1,14 +0,0 @@ -{{template "header.html" .}} - - - - - -{{range .fortunes}} - - - - -{{end}} -
idmessage
{{.Id}}{{.Message}}
-{{template "footer.html" .}} diff --git a/frameworks/Go/revel/src/benchmark/app/views/footer.html b/frameworks/Go/revel/src/benchmark/app/views/footer.html deleted file mode 100644 index 308b1d01b6c..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/views/footer.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/frameworks/Go/revel/src/benchmark/app/views/header.html b/frameworks/Go/revel/src/benchmark/app/views/header.html deleted file mode 100644 index d543e6a8c3e..00000000000 --- a/frameworks/Go/revel/src/benchmark/app/views/header.html +++ /dev/null @@ -1,6 +0,0 @@ - - - -Fortunes - - diff --git a/frameworks/Go/revel/src/benchmark/conf/app.conf b/frameworks/Go/revel/src/benchmark/conf/app.conf deleted file mode 100644 index 8a77dcda352..00000000000 --- a/frameworks/Go/revel/src/benchmark/conf/app.conf +++ /dev/null @@ -1,40 +0,0 @@ -app.name=benchmark -http.addr=0.0.0.0 -http.port=8080 - -db.driver = mysql -db.import = github.com/go-sql-driver/mysql -db.spec = benchmarkdbuser:benchmarkdbpass@tcp(tfb-database:3306)/hello_world -package.folders=conf,app/views - -results.pretty=false -results.chunked=false - -[dev] -mode.dev=true -watch=true - -log.trace.output = stderr -log.info.output = stderr -log.warn.output = stderr -log.error.output = stderr - -[prod] -mode.dev=false -watch=false - -log.trace.output = off -log.info.output = off -log.warn.output = stderr -log.error.output = stderr - -[prod-fasthttp] -mode.dev=false -watch=false -module.fasthttp=github.com/revel/modules/server-engine/fasthttp -server.engine=fasthttp - -log.trace.output = off -log.info.output = off -log.warn.output = stderr -log.error.output = stderr diff --git a/frameworks/Go/revel/src/benchmark/conf/routes b/frameworks/Go/revel/src/benchmark/conf/routes deleted file mode 100644 index 0fbef41c22b..00000000000 --- a/frameworks/Go/revel/src/benchmark/conf/routes +++ /dev/null @@ -1,15 +0,0 @@ -# Routes -# This file defines all application routes (Higher priority routes first) -# ~~~~ - -GET /plaintext App.Plaintext -GET /json App.Json -GET /db App.Db -GET /fortune App.Fortune -GET /update App.Update -GET /jet-db App.JetDb -GET /jet-fortune App.JetFortune -GET /jet-update App.JetUpdate -GET /qbs-db App.QbsDb -GET /qbs-fortune App.QbsFortune -GET /qbs-update App.QbsUpdate diff --git a/frameworks/Go/sprapp/README.md b/frameworks/Go/sprapp/README.md index 528e027ff42..12282792c12 100644 --- a/frameworks/Go/sprapp/README.md +++ b/frameworks/Go/sprapp/README.md @@ -1,4 +1,4 @@ -SPRAPP https://github.com/cloudxaas/sprapp/ +SPRAPP https://github.com/cloudxaas/gosprapp ### PLAINTEXT diff --git a/frameworks/Haskell/snap/README.md b/frameworks/Haskell/snap/README.md deleted file mode 100644 index b8fc83b133a..00000000000 --- a/frameworks/Haskell/snap/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Snap Benchmarking Test - -This is the Snap portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -* [Source](bench/src/Main.hs) -* [Configurations](bench/cfg/db.cfg) - -## Infrastructure Software Versions -The tests were run with: -* GHC 7.10.3 -* snap-core 0.9.8.0 -* snap-server 0.9.5.1 -* aeson 0.11.2.0 -* configurator 0.3.0.0 -* resource-pool 0.2.3.2 -* mysql-simple 0.2.2.5 - -## Test URLs -### JSON Encoding Test - -http://localhost:8000/json - -### Data-Store/Database Mapping Test - -http://localhost:8000/db - -### Variable Query Test - -http://localhost:8000/db?queries=2 diff --git a/frameworks/Haskell/snap/bench/cfg/db.cfg b/frameworks/Haskell/snap/bench/cfg/db.cfg deleted file mode 100644 index 736f4ec34c8..00000000000 --- a/frameworks/Haskell/snap/bench/cfg/db.cfg +++ /dev/null @@ -1,5 +0,0 @@ -host="tfb-database" -uname="benchmarkdbuser" -pword="benchmarkdbpass" -dbase="hello_world" -dport="3306" diff --git a/frameworks/Haskell/snap/bench/snap-bench.cabal b/frameworks/Haskell/snap/bench/snap-bench.cabal deleted file mode 100644 index 2f9a58f4378..00000000000 --- a/frameworks/Haskell/snap/bench/snap-bench.cabal +++ /dev/null @@ -1,30 +0,0 @@ -Name: snap-bench -Version: 0.1 -Synopsis: Snap test for benchmark tests -Description: Simple web services to benchmark the Snap web server -License: BSD3 -Author: Steve Smith -Maintainer: guntir@teamclerks.net -Stability: Experimental -Category: Web -Build-type: Simple -Cabal-version: >=1.2 - -Executable snap-bench - hs-source-dirs: src - main-is: Main.hs - - Build-depends: base - , aeson - , bytestring - , configurator - , mysql-simple - , random - , resource-pool - , snap-core - , snap-server - , text - , unordered-containers - - ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2 - -fno-warn-unused-do-bind -rtsopts diff --git a/frameworks/Haskell/snap/bench/src/Main.hs b/frameworks/Haskell/snap/bench/src/Main.hs deleted file mode 100644 index f4b7f9fab45..00000000000 --- a/frameworks/Haskell/snap/bench/src/Main.hs +++ /dev/null @@ -1,104 +0,0 @@ -{-# LANGUAGE BangPatterns, OverloadedStrings #-} - -module Main where - -import Control.Applicative -import Control.Monad -import Control.Monad.IO.Class -import Data.Aeson -import Data.Configurator -import Data.Int -import Data.Text (Text) -import Data.Pool -import Database.MySQL.Simple -import Database.MySQL.Simple.Result -import Database.MySQL.Simple.QueryResults -import Prelude hiding (lookup) -import Snap.Core -import Snap.Http.Server -import System.Random - -import qualified Data.HashMap.Lazy as HM -import qualified Data.ByteString.Char8 as B - -data RandQuery = RQ !Int !Int - -instance ToJSON RandQuery where - toJSON (RQ i n) = object ["id" .= i, "randomNumber" .= n] - -instance QueryResults RandQuery where - convertResults [fa, fb] [va, vb] = RQ a b - where - !a = convert fa va - !b = convert fb vb - convertResults fs vs = convertError fs vs 2 - -main :: IO () -main = do - db <- load [Required "cfg/db.cfg"] - foos <- mapM (lookup db) ["host", "uname", "pword", "dbase", "dport"] - let foos' = sequence foos - maybe (putStrLn "No foo") dbSetup foos' - -dbSetup :: [String] -> IO () -dbSetup sets = do - pool <- createPool (connect $ getConnInfo sets) close 1 10 50 - httpServe config $ site pool - -config :: Config Snap a -config = setAccessLog ConfigNoLog - . setErrorLog ConfigNoLog - . setPort 8000 - $ defaultConfig - -getConnInfo :: [String] -> ConnectInfo -getConnInfo [host, user, pwd, db, port] = defaultConnectInfo - { connectHost = host - , connectUser = user - , connectPassword = pwd - , connectDatabase = db - , connectPort = read port - } -getConnInfo _ = defaultConnectInfo - -site :: Pool Connection -> Snap () -site pool = route - [ ("json", jsonHandler) - , ("db", dbHandler pool) - , ("dbs", dbsHandler pool) - , ("plaintext", plaintextHandler pool) - ] - -jsonHandler :: Snap () -jsonHandler = do - modifyResponse (setContentType "application/json") - writeLBS $ encode ( Object $ HM.singleton "message" (String "Hello, World!") ) - -dbHandler :: Pool Connection -> Snap () -dbHandler pool = do - modifyResponse (setContentType "application/json") - r <- liftIO $ randomRIO (1, 10000) - qry <- liftIO $ withResource pool (flip runOne r) - writeLBS $ encode qry - -dbsHandler :: Pool Connection -> Snap () -dbsHandler pool = do - modifyResponse (setContentType "application/json") - qs <- getQueryParam "queries" - runAll pool $ maybe 1 fst (qs >>= B.readInt) - -plaintextHandler :: Pool Connection -> Snap () -plaintextHandler pool = do - modifyResponse (setContentType "text/plain") - writeBS "Hello, World!" - -runAll :: Pool Connection -> Int -> Snap () -runAll pool i | i < 1 = runAll pool 1 - | i > 500 = runAll pool 500 - | otherwise = do - !rs <- take i . randomRs (1, 10000) <$> liftIO newStdGen - qry <- liftIO $ withResource pool (forM rs . runOne) - writeLBS $ encode qry - -runOne :: Connection -> Int -> IO RandQuery -runOne conn = fmap head . query conn "SELECT * FROM World where id=?" . Only diff --git a/frameworks/Haskell/snap/bench/stack.yaml b/frameworks/Haskell/snap/bench/stack.yaml deleted file mode 100644 index fff8b706b69..00000000000 --- a/frameworks/Haskell/snap/bench/stack.yaml +++ /dev/null @@ -1,5 +0,0 @@ -flags: {} -packages: -- '.' -extra-deps: [] -resolver: lts-10.0 diff --git a/frameworks/Haskell/snap/benchmark_config.json b/frameworks/Haskell/snap/benchmark_config.json deleted file mode 100644 index d11a53f007c..00000000000 --- a/frameworks/Haskell/snap/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "snap", - "tests": [{ - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/dbs?queries=", - "plaintext_url": "/plaintext", - "port": 8000, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "Snap", - "language": "Haskell", - "flavor": "GHC78", - "orm": "Full", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Snap", - "notes": "", - "versus": "", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Haskell/snap/config.toml b/frameworks/Haskell/snap/config.toml deleted file mode 100644 index fdc8f0f1740..00000000000 --- a/frameworks/Haskell/snap/config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[framework] -name = "snap" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/dbs?queries=" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "None" -webserver = "None" -versus = "" diff --git a/frameworks/Haskell/snap/snap.dockerfile b/frameworks/Haskell/snap/snap.dockerfile deleted file mode 100644 index d28d0872e5f..00000000000 --- a/frameworks/Haskell/snap/snap.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM haskell:8.6.3 - -RUN apt-get update -yqq && apt-get install -yqq xz-utils make netbase -RUN apt-get install -yqq default-libmysqlclient-dev pkg-config libpcre3 libpcre3-dev - -COPY ./bench /snap -WORKDIR /snap - -RUN stack upgrade -RUN stack --allow-different-user build --install-ghc - -EXPOSE 8000 - -CMD stack --allow-different-user exec snap-bench -- +RTS -A4M -N -qg2 -I0 -G2 diff --git a/frameworks/Haskell/warp/benchmark_config.json b/frameworks/Haskell/warp/benchmark_config.json index e96726ac64d..ff383c6c7f8 100644 --- a/frameworks/Haskell/warp/benchmark_config.json +++ b/frameworks/Haskell/warp/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "warp", + "maintainers": ["cptwunderlich"], "tests": [{ "default": { "json_url": "/json", @@ -48,30 +49,6 @@ "notes": "Uses libpq system dependency.", "dockerfile": "warp-shared.dockerfile", "tags": [] - }, - "mysql-haskell": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 7041, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "Warp", - "language": "Haskell", - "flavor": "GHC910", - "orm": "Raw", - "platform": "Wai", - "webserver": "Wai", - "os": "Linux", - "database_os": "Linux", - "display_name": "Warp+mysql-haskell", - "notes": "Pure Haskell.", - "dockerfile": "warp-shared.dockerfile", - "tags": ["broken"] } }] } diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs b/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs index 3b1ed8e52f5..4a23d0ef365 100644 --- a/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs +++ b/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs @@ -1,6 +1,7 @@ {-# OPTIONS -Wno-orphans #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE QuasiQuotes #-} module TFB.Db ( Pool, @@ -20,10 +21,13 @@ import Data.Bifunctor qualified as Bi import Data.ByteString (ByteString) import Data.ByteString.Char8 qualified as BSC import Data.Either qualified as Either +import Data.List (sortBy) +import Data.Ord (comparing) import Data.Pool qualified as Pool import Database.PostgreSQL.Simple (SomePostgreSqlException) import Database.PostgreSQL.Simple qualified as PG import Database.PostgreSQL.Simple.FromRow (FromRow (fromRow), field) +import Database.PostgreSQL.Simple.SqlQQ (sql) import System.IO.Error qualified as Error import TFB.Types qualified as Types @@ -132,12 +136,15 @@ queryWorldByIds dbPool wIds = Pool.withResource dbPool $ \conn -> do updateWorlds :: Pool -> [(Types.World, Int)] -> IO (Either Error [Types.World]) updateWorlds dbPool wsUpdates = Pool.withResource dbPool $ \conn -> do - let worlds = Bi.first Types.wId <$> wsUpdates + let worlds = sortBy (comparing fst) $ Bi.first Types.wId <$> wsUpdates res <- try @SomePostgreSqlException $ PG.executeMany conn - "UPDATE World SET randomNumber = upd.rnd FROM (VALUES (?,?)) as upd(wid,rnd) WHERE World.id = upd.wid" + [sql| UPDATE World + SET randomNumber = upd.rnd + FROM (VALUES (?,?)) as upd(wid,rnd) + WHERE World.id = upd.wid |] worlds _ <- case res of Left e -> print e diff --git a/frameworks/Haskell/warp/stack.yaml b/frameworks/Haskell/warp/stack.yaml index 7df4cd85668..7776027f322 100644 --- a/frameworks/Haskell/warp/stack.yaml +++ b/frameworks/Haskell/warp/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-24.11 +resolver: lts-24.29 packages: - ./shared/tfb-types @@ -12,5 +12,5 @@ extra-deps: - mysql-haskell-1.1.7 # the following flags are meant for use with warp.dockerfile -compiler: ghc-9.10.2 # this MUST match the resolver's GHC; minor hack to ensure GHC isn't downloaded into sandbox. +compiler: ghc-9.10.3 # this MUST match the resolver's GHC; minor hack to ensure GHC isn't downloaded into sandbox. allow-different-user: true diff --git a/frameworks/Haskell/warp/stack.yaml.lock b/frameworks/Haskell/warp/stack.yaml.lock index 16819ffff37..f0484238959 100644 --- a/frameworks/Haskell/warp/stack.yaml.lock +++ b/frameworks/Haskell/warp/stack.yaml.lock @@ -20,7 +20,7 @@ packages: hackage: mysql-haskell-1.1.7 snapshots: - completed: - sha256: 468e1afa06cd069e57554f10e84fdf1ac5e8893e3eefc503ef837e2449f7e60c - size: 726310 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/11.yaml - original: lts-24.11 + sha256: b7dc388c75a62a8a2f1ac753f3bfc3f43a3a2cb58d8a920272cc9a049ff76c62 + size: 726792 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/29.yaml + original: lts-24.29 diff --git a/frameworks/Haskell/warp/warp-shared.dockerfile b/frameworks/Haskell/warp/warp-shared.dockerfile index 635674f2f46..a6a72eeea70 100644 --- a/frameworks/Haskell/warp/warp-shared.dockerfile +++ b/frameworks/Haskell/warp/warp-shared.dockerfile @@ -1,10 +1,10 @@ -FROM haskell:9.10-slim-bullseye +FROM haskell:9.10.3-slim-bookworm RUN apt-get update -yqq && apt-get install -yqq xz-utils make curl ca-certificates RUN install -d /usr/share/postgresql-common/pgdg RUN curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc RUN . /etc/os-release -RUN sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt bullseye-pgdg main' > /etc/apt/sources.list.d/pgdg.list" +RUN sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main' > /etc/apt/sources.list.d/pgdg.list" RUN apt-get update && apt-get install -yqq libpq-dev WORKDIR /app diff --git a/frameworks/Haskell/wizzardo-inline/benchmark_config.json b/frameworks/Haskell/wizzardo-inline/benchmark_config.json index 6bb2887050b..1a9ea1aa6c0 100755 --- a/frameworks/Haskell/wizzardo-inline/benchmark_config.json +++ b/frameworks/Haskell/wizzardo-inline/benchmark_config.json @@ -20,7 +20,8 @@ "database_os": "Linux", "display_name": "wizzardo-inline", "notes": "", - "versus": "warp" + "versus": "warp", + "tags": ["broken"] } } ] diff --git a/frameworks/Java/act/benchmark_config.json b/frameworks/Java/act/benchmark_config.json index dc64188a8ef..4af9ac74ff6 100644 --- a/frameworks/Java/act/benchmark_config.json +++ b/frameworks/Java/act/benchmark_config.json @@ -120,7 +120,8 @@ "database_os": "Linux", "display_name": "act-eclipselink-pgsql", "notes": "", - "versus": "undertow-postgresql" + "versus": "undertow-postgresql", + "tags": ["broken"] }, "eclipselink-pgsql-rythm": { "fortune_url": "/fortunes", diff --git a/frameworks/Java/activeweb/README.md b/frameworks/Java/activeweb/README.md deleted file mode 100644 index c71a156714b..00000000000 --- a/frameworks/Java/activeweb/README.md +++ /dev/null @@ -1,28 +0,0 @@ -ActiveWeb Benchmark App -======================== -This is a Framework Benchmark Test for ActiveWeb - -For more information, please see: - -* http://www.techempower.com/benchmarks/ -* http://javalite.io - -How to start locally -========================= - -1. Execute this script against local MySQL DB: - - https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/config/create.sql - -2. Start application: - -``` - export ACTIVE_ENV=local - mvn jetty:run -``` - -3. Access this URL with browser: - - http://localhost:8080/activeweb-benchmark/ - - diff --git a/frameworks/Java/activeweb/activeweb-jackson.dockerfile b/frameworks/Java/activeweb/activeweb-jackson.dockerfile deleted file mode 100644 index d25e2f1dd45..00000000000 --- a/frameworks/Java/activeweb/activeweb-jackson.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM maven:3.6.1-jdk-11-slim as maven -WORKDIR /activeweb -COPY pom.xml pom.xml -COPY scripts scripts -COPY src src -RUN mvn package -DskipTests -q - -FROM openjdk:11.0.3-jdk-stretch -WORKDIR /resin -RUN curl -sL http://caucho.com/download/resin-4.0.61.tar.gz | tar xz --strip-components=1 -RUN rm -rf webapps/* -COPY --from=maven /activeweb/target/activeweb.war webapps/ROOT.war -COPY resin.xml conf/resin.xml - -EXPOSE 8080 - -CMD ["java", "-jar", "lib/resin.jar", "console"] diff --git a/frameworks/Java/activeweb/activeweb.dockerfile b/frameworks/Java/activeweb/activeweb.dockerfile deleted file mode 100644 index d25e2f1dd45..00000000000 --- a/frameworks/Java/activeweb/activeweb.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM maven:3.6.1-jdk-11-slim as maven -WORKDIR /activeweb -COPY pom.xml pom.xml -COPY scripts scripts -COPY src src -RUN mvn package -DskipTests -q - -FROM openjdk:11.0.3-jdk-stretch -WORKDIR /resin -RUN curl -sL http://caucho.com/download/resin-4.0.61.tar.gz | tar xz --strip-components=1 -RUN rm -rf webapps/* -COPY --from=maven /activeweb/target/activeweb.war webapps/ROOT.war -COPY resin.xml conf/resin.xml - -EXPOSE 8080 - -CMD ["java", "-jar", "lib/resin.jar", "console"] diff --git a/frameworks/Java/activeweb/benchmark_config.json b/frameworks/Java/activeweb/benchmark_config.json deleted file mode 100644 index d2efeface79..00000000000 --- a/frameworks/Java/activeweb/benchmark_config.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "framework": "activeweb", - "tests": [{ - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "ActiveWeb", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Servlet", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ActiveWeb", - "notes": "", - "versus": "servlet", - "tags": ["broken"] - }, - "jackson": { - "json_url": "/json/jackson", - "db_url": "/db/jackson", - "query_url": "/queries/jackson?queries=", - "update_url": "/updates/jackson?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "ActiveWeb", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Servlet", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ActiveWeb", - "notes": "", - "versus": "servlet", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Java/activeweb/config.toml b/frameworks/Java/activeweb/config.toml deleted file mode 100644 index 83c43835a3a..00000000000 --- a/frameworks/Java/activeweb/config.toml +++ /dev/null @@ -1,34 +0,0 @@ -[framework] -name = "activeweb" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Servlet" -webserver = "None" -versus = "servlet" - -[jackson] -urls.json = "/json/jackson" -urls.db = "/db/jackson" -urls.query = "/queries/jackson?queries=" -urls.update = "/updates/jackson?queries=" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Servlet" -webserver = "None" -versus = "servlet" diff --git a/frameworks/Java/activeweb/pom.xml b/frameworks/Java/activeweb/pom.xml deleted file mode 100644 index 2f073f2424d..00000000000 --- a/frameworks/Java/activeweb/pom.xml +++ /dev/null @@ -1,154 +0,0 @@ - - 4.0.0 - - org.javalite - activeweb-benchmark - war - 1.1-SNAPSHOT - ActiveWeb Benchmark App - - - UTF-8 - 11 - 11 - 1.11 - 1.4.10 - - - - activeweb - - - org.apache.maven.plugins - maven-surefire-plugin - 2.18.1 - - brief - true - false - - **/*Spec*.java - **/*Test*.java - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - false - - - - - org.mortbay.jetty - maven-jetty-plugin - 6.1.22 - - 0 - - - 8080 - 1000 - - - - - - - - - - - - org.javalite - activejdbc-instrumentation - ${activejdbc.version} - - - process-classes - - instrument - - - - - - - - - - junit - junit - 4.13.1 - test - - - org.javalite - activeweb - ${activeweb.version} - - - org.javalite - activejdbc - ${activejdbc.version} - - - org.javalite - activeweb-testing - ${activeweb.version} - test - - - - mysql - mysql-connector-java - 8.0.28 - - - org.slf4j - slf4j-simple - 1.8.0-beta4 - - - com.fasterxml.jackson.core - jackson-core - 2.15.0 - - - com.fasterxml.jackson.core - jackson-databind - 2.16.0 - - - - - - javaLite-snapshots - JavaLite Snapshots - http://repo.javalite.io/ - - false - - - true - - - - - - javaLite-plugin-snapshots - JavaLite Plugin Snapshots - http://repo.javalite.io/ - - false - - - true - - - - - diff --git a/frameworks/Java/activeweb/resin.xml b/frameworks/Java/activeweb/resin.xml deleted file mode 100755 index 5041ba51e4f..00000000000 --- a/frameworks/Java/activeweb/resin.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frameworks/Java/activeweb/scripts/README b/frameworks/Java/activeweb/scripts/README deleted file mode 100644 index 758f7b5b0e9..00000000000 --- a/frameworks/Java/activeweb/scripts/README +++ /dev/null @@ -1,4 +0,0 @@ -All scripts are intended to be run from a root directory: - -$./scripts/instrument.sh - diff --git a/frameworks/Java/activeweb/scripts/instrument.sh b/frameworks/Java/activeweb/scripts/instrument.sh deleted file mode 100755 index 49209086385..00000000000 --- a/frameworks/Java/activeweb/scripts/instrument.sh +++ /dev/null @@ -1 +0,0 @@ -mvn -o clean process-classes diff --git a/frameworks/Java/activeweb/src/main/java/app/config/AppBootstrap.java b/frameworks/Java/activeweb/src/main/java/app/config/AppBootstrap.java deleted file mode 100644 index 93b6de8eda4..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/config/AppBootstrap.java +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.config; - -import org.javalite.activeweb.AppContext; -import org.javalite.activeweb.Bootstrap; -import org.javalite.templator.TemplatorConfig; - -/** - * @author Igor Polevoy - */ -public class AppBootstrap extends Bootstrap { - public void init(AppContext context) { - TemplatorConfig.instance().cacheTemplates(true); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/config/AppControllerConfig.java b/frameworks/Java/activeweb/src/main/java/app/config/AppControllerConfig.java deleted file mode 100644 index 2d653fe0b03..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/config/AppControllerConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.config; - - -import app.controllers.DbController; -import app.controllers.FortunesController; -import app.controllers.QueriesController; -import app.controllers.UpdatesController; -import org.javalite.activeweb.AbstractControllerConfig; -import org.javalite.activeweb.AppContext; -import org.javalite.activeweb.controller_filters.DBConnectionFilter; - - -/** - * @author Igor Polevoy - */ -public class AppControllerConfig extends AbstractControllerConfig { - - public void init(AppContext context) { -// addGlobalFilters(new TimingFilter()); for speed - not sure how logging is configured - - add(new DBConnectionFilter()).to(DbController.class, QueriesController.class, - FortunesController.class, UpdatesController.class); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/config/DbConfig.java b/frameworks/Java/activeweb/src/main/java/app/config/DbConfig.java deleted file mode 100644 index 579d02eb69c..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/config/DbConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.config; - -import org.javalite.activeweb.AbstractDBConfig; -import org.javalite.activeweb.AppContext; - -/** - * @author Igor Polevoy - */ -public class DbConfig extends AbstractDBConfig { - public void init(AppContext context) { - - String jdbcParams = "jdbcCompliantTruncation=false&elideSetAutoCommits=true" + - "&useLocalSessionState=true" + - "&cachePrepStmts=true" + - "&cacheCallableStmts=true" + - "&alwaysSendSetIsolation=false" + - "&prepStmtCacheSize=4096" + - "&cacheServerConfiguration=true" + - "&prepStmtCacheSqlLimit=2048" + - "&zeroDateTimeBehavior=convertToNull" + - "&traceProtocol=false" + - "&useUnbufferedInput=false" + - "&useReadAheadInput=false" + - "&maintainTimeStats=false" + - "&useServerPrepStmts=true" + - "&cacheRSMetadata=true" + - "&useSSL=false"; - - environment("development").jndi("java:comp/env/jdbc/hello_world"); - - //need to set ACTIVE_ENV=local to run on dev box. - environment("local").jdbc("com.mysql.cj.jdbc.Driver", "jdbc:mysql://tfb-database/hello_world?" + jdbcParams, "benchmarkdbuser", "benchmarkdbpass"); - - environment("development").testing().jdbc("com.mysql.cj.jdbc.Driver", "jdbc:mysql://tfb-database/hello_world?" + jdbcParams, "benchmarkdbuser", "benchmarkdbpass"); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/config/RouteConfig.java b/frameworks/Java/activeweb/src/main/java/app/config/RouteConfig.java deleted file mode 100644 index 0bc41c4e898..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/config/RouteConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * @author Igor Polevoy: 1/9/14 11:26 PM - */ - -package app.config; - -import org.javalite.activeweb.AbstractRouteConfig; -import org.javalite.activeweb.AppContext; - -public class RouteConfig extends AbstractRouteConfig { - @Override public void init(AppContext appContext) { - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/DbController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/DbController.java deleted file mode 100644 index f1635f91c47..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/DbController.java +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import app.models.World; -import java.io.IOException; -import org.javalite.activeweb.AppController; - -import java.util.concurrent.ThreadLocalRandom; - -/** - * @author Igor Polevoy: 12/18/13 4:36 PM - * @author Eric Nielsen - */ -public class DbController extends AppController { - public void index() { - respond(World.findById(randomNumber()).toJson(false, "id", "randomNumber")).contentType("application/json"); - } - - public void jackson() throws IOException { - JsonController.WRITER.writeValue(outputStream("application/json"), World.findById(randomNumber())); - } - - protected int randomNumber(){ - return ThreadLocalRandom.current().nextInt(10000) + 1; - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/FortunesController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/FortunesController.java deleted file mode 100644 index 8db24d01474..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/FortunesController.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import app.models.Fortune; -import org.javalite.activeweb.AppController; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * @author Igor Polevoy: 12/18/13 9:11 PM - * @author Eric Nielsen - */ -public class FortunesController extends AppController { - public void index() { - List dbFortunes = Fortune.findAll(); - List fortunes = new ArrayList(dbFortunes); - fortunes.add(Fortune.create("id", 0, "message", "Additional fortune added at request time.")); - Collections.sort(fortunes); - view("fortunes", fortunes); - render("/fortunes/index").noLayout(); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/HomeController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/HomeController.java deleted file mode 100644 index 9f7464b4f15..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/HomeController.java +++ /dev/null @@ -1,26 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package app.controllers; - -import org.javalite.activeweb.AppController; - -/** - * @author Igor Polevoy - */ -public class HomeController extends AppController { - public void index(){} -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/JsonController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/JsonController.java deleted file mode 100644 index f09f0756cfe..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/JsonController.java +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import app.models.Message; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import java.io.IOException; -import org.javalite.activeweb.AppController; - - -/** - * @author Igor Polevoy: 12/18/13 3:51 PM - * @author Eric Nielsen - */ -public class JsonController extends AppController { - static final ObjectWriter WRITER = new ObjectMapper().writer(); - - public void index() { - view("message", new Message("Hello, World!")); - render("/json/index").noLayout().contentType("application/json"); - } - - public void jackson() throws IOException { - WRITER.writeValue(outputStream("application/json"), new Message("Hello, World!")); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/PlaintextController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/PlaintextController.java deleted file mode 100644 index 4e20e3306a8..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/PlaintextController.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import org.javalite.activeweb.AppController; - -/** - * @author Igor Polevoy: 12/19/13 1:23 AM - * @author Eric Nielsen - */ -public class PlaintextController extends AppController { - public void index() { - respond("Hello, World!").contentType("text/plain"); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/QueriesController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/QueriesController.java deleted file mode 100644 index 24599546686..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/QueriesController.java +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import app.models.World; -import java.io.IOException; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Igor Polevoy: 12/18/13 4:36 PM - * @author Eric Nielsen - */ -public class QueriesController extends DbController { - @Override public void index() { - view("worlds", getWorlds()); - render("/queries/index").contentType("application/json"); - } - - @Override public void jackson() throws IOException { - JsonController.WRITER.writeValue(outputStream("application/json"), getWorlds()); - } - - @Override protected String getLayout() { - return null; - } - - protected List getWorlds() { - int number = getQueries(); - List worlds = new ArrayList<>(number); - for (int i = 0; i < number; i++) { - worlds.add(World.findById(randomNumber())); - } - return worlds; - } - - protected int getQueries() { - int queries; - try { - queries = Integer.parseInt(param("queries")); - } catch (Exception e) { - queries = 1; - } - if (queries > 500) { - queries = 500; - } else if (queries < 1) { - queries = 1; - } - return queries; - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/controllers/UpdatesController.java b/frameworks/Java/activeweb/src/main/java/app/controllers/UpdatesController.java deleted file mode 100644 index 77472801edf..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/controllers/UpdatesController.java +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import app.models.World; - -import java.util.List; - -/** - * @author Igor Polevoy: 12/18/13 9:51 PM - * @author Eric Nielsen - */ -public class UpdatesController extends QueriesController { - - @Override protected List getWorlds() { - List worlds = super.getWorlds(); - for (World world : worlds) { - world.set("randomNumber", randomNumber()).saveIt(); - } - return worlds; - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/models/Fortune.java b/frameworks/Java/activeweb/src/main/java/app/models/Fortune.java deleted file mode 100644 index d32e0b4f97e..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/models/Fortune.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * @author Igor Polevoy: 12/18/13 9:12 PM - */ - -package app.models; - -import org.javalite.activejdbc.Model; -import org.javalite.activejdbc.annotations.Table; - -@Table("Fortune") -public class Fortune extends Model implements Comparable { - @Override public int compareTo(Fortune other) { - return getString("message").compareTo(other.getString("message")); - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/models/Message.java b/frameworks/Java/activeweb/src/main/java/app/models/Message.java deleted file mode 100644 index 70dd834e0b1..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/models/Message.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.models; - -/** - * @author Eric Nielsen - */ -public class Message { - private String message; - - public Message() { - } - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/frameworks/Java/activeweb/src/main/java/app/models/World.java b/frameworks/Java/activeweb/src/main/java/app/models/World.java deleted file mode 100644 index ca199991f15..00000000000 --- a/frameworks/Java/activeweb/src/main/java/app/models/World.java +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.javalite.activejdbc.Model; -import org.javalite.activejdbc.annotations.Table; - -/** - * @author Igor Polevoy: 12/18/13 4:32 PM - * @author Eric Nielsen - */ -@Table("World") -@JsonIgnoreProperties({"frozen", "idName", "longId", "new", "valid"}) -public class World extends Model { - public Object getRandomNumber() { - return get("randomNumber"); - } -} diff --git a/frameworks/Java/activeweb/src/main/resources/activeweb.properties b/frameworks/Java/activeweb/src/main/resources/activeweb.properties deleted file mode 100644 index eb727c0b512..00000000000 --- a/frameworks/Java/activeweb/src/main/resources/activeweb.properties +++ /dev/null @@ -1 +0,0 @@ -templateManager=org.javalite.activeweb.templator.TemplatorManager \ No newline at end of file diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/jetty-env.xml b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/jetty-env.xml deleted file mode 100644 index c7deb638da7..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/jetty-env.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/resin-web.xml b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/resin-web.xml deleted file mode 100644 index bfcecd44db6..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/resin-web.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - com.mysql.cj.jdbc.MysqlConnectionPoolDataSource - jdbc:mysql://tfb-database:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts=true&cacheRSMetadata=true&useSSL=false - benchmarkdbuser - benchmarkdbpass - - - - - - diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/fortunes/index.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/fortunes/index.html deleted file mode 100644 index 4406df33ba1..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/fortunes/index.html +++ /dev/null @@ -1 +0,0 @@ -Fortunes<#list fortunes as fortune >
idmessage
${fortune.id}${fortune.message esc}
\ No newline at end of file diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/home/index.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/home/index.html deleted file mode 100644 index 6ef9c63ec73..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/home/index.html +++ /dev/null @@ -1,24 +0,0 @@ -

Available tests:

- - - - diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/json/index.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/json/index.html deleted file mode 100644 index 3a71ebcbe09..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/json/index.html +++ /dev/null @@ -1 +0,0 @@ -{"message":"${message.message}"} \ No newline at end of file diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/layouts/default_layout.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/layouts/default_layout.html deleted file mode 100644 index 929d5f75bc6..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/layouts/default_layout.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - ActiveWeb - - - -
- - - -
- ${page_content} -
- - -
- - - - diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/queries/index.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/queries/index.html deleted file mode 100644 index bb2557ab08c..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/queries/index.html +++ /dev/null @@ -1 +0,0 @@ - [<#list worlds as w >{"id":${w.id},"randomNumber":${w.randomNumber}}<#if w_has_next >,] \ No newline at end of file diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/system/404.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/system/404.html deleted file mode 100644 index a4f41cf6d53..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/system/404.html +++ /dev/null @@ -1,3 +0,0 @@ -<@content for="title">404 Not Found -

404 - Resource Not Found

-${message!} diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/system/error.html b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/system/error.html deleted file mode 100644 index aae2c86dab4..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/views/system/error.html +++ /dev/null @@ -1,18 +0,0 @@ -Error:
-
-${message}
-
- - -
-See Stack Trace - - \ No newline at end of file diff --git a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/web.xml b/frameworks/Java/activeweb/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 8b389f934fa..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - activeweb - - - dispatcher - org.javalite.activeweb.RequestDispatcher - - exclusions - css,images,.js - - - encoding - UTF-8 - - - - root_controller - home - - - - - dispatcher - /* - - diff --git a/frameworks/Java/activeweb/src/main/webapp/css/main.css b/frameworks/Java/activeweb/src/main/webapp/css/main.css deleted file mode 100644 index 2cabbd84356..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/css/main.css +++ /dev/null @@ -1,74 +0,0 @@ -@charset "UTF-8"; -/* CSS Document */ - -*{ - margin:0; - padding:0; -} - -html, body{ - background:white; -} - -a{ - text-decoration:none; - outline:none; -} - -a:hover{ - text-decoration:underline; -} - -p{ - margin:10px 0; - line-height:16px; -} - - -.header{ - background-color:#fafad2; - padding:20px; -} - -.main{ - padding:20px -} - -.content{ - padding:20px; -} - -.error{ - color:red; -} - -.error_message{ - background-color:#ffb6c1; - - margin-top:10px; - margin-bottom:10px; - height:0; -} - -.message{ - background-color:#7fffd4; - - margin-top:10px; - margin-bottom:10px; -} - -.footer{ - background-color:#fafad2; - padding:20px; -} - -ul{ - margin: 20px; -} - - -table tr td{ - background-color:#dcdcdc; - padding:10px; -} - diff --git a/frameworks/Java/activeweb/src/main/webapp/js/aw.js b/frameworks/Java/activeweb/src/main/webapp/js/aw.js deleted file mode 100644 index cd71f3cbef3..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/js/aw.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright 2009-2010 Igor Polevoy - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -/* - This file is a collection of unobtrusive JS that binds to link_to generated anchors typical for Ajax calls. - - author: Igor Polevoy - */ - -$(document).ready(function() { - $('a[data-link]').bind('click', function() { - var anchor = $(this); - var destination = anchor.attr("data-destination"); - var formId = anchor.attr("data-form"); - var href = anchor.attr("href"); - var _method = anchor.attr("data-method"); - var before = anchor.attr("data-before"); - var after = anchor.attr("data-after"); - var beforeArg = anchor.attr("data-before-arg"); - var afterArg = anchor.attr("data-after-arg"); - var error = anchor.attr("data-error"); - - var confirmMessage = anchor.attr("data-confirm"); - - if(confirmMessage != null ){ - if(!confirm(confirmMessage)){ - return false; - } - } - - //not Ajax - if(destination == null && before == null && after == null && (_method == null || _method.toLowerCase() == "get")){ - return true; - } - - if (_method == null) { - _method = "get"; - } - var type; - if (_method.toLowerCase() == "get") { - type = "get"; - } else if (_method.toLowerCase() == "post" - || _method.toLowerCase() == "put" - || _method.toLowerCase() == "delete") { - type = "post"; - } - - var data = "_method=" + _method; - if (formId != null) { - data += "&" + $("#" + formId).serialize(); - } - - if(before != null){ - eval(before)(beforeArg); - } - - - $.ajax({ url: href, data: data, type:type, - success: function(data) { - if (after != null) - eval(after)(afterArg, data); - - if (destination != null) - $("#" + destination).html(data); - }, - error: function(xhr, status, errorThrown) { - if(error != null){ - eval(error)(xhr.status, xhr.responseText ); - } - } - }); - - return false; - }); -}); diff --git a/frameworks/Java/activeweb/src/main/webapp/js/jquery-1.4.2.min.js b/frameworks/Java/activeweb/src/main/webapp/js/jquery-1.4.2.min.js deleted file mode 100644 index 7c243080233..00000000000 --- a/frameworks/Java/activeweb/src/main/webapp/js/jquery-1.4.2.min.js +++ /dev/null @@ -1,154 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/frameworks/Java/activeweb/src/test/java/app/controllers/DbControllerSpec.java b/frameworks/Java/activeweb/src/test/java/app/controllers/DbControllerSpec.java deleted file mode 100644 index 1319915f04e..00000000000 --- a/frameworks/Java/activeweb/src/test/java/app/controllers/DbControllerSpec.java +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import org.junit.Test; - -import java.util.Map; -import org.junit.Ignore; - -/** - * @author Igor Polevoy: 12/18/13 4:42 PM - * @author Eric Nielsen - */ -public class DbControllerSpec extends org.javalite.activeweb.DBControllerSpec { - - @Test - public void shouldRenderOneRecord() { - //execute controller - request().get("index"); - //process result - System.out.println(responseContent()); - Map result = JsonHelper.toMap(responseContent()); - //test result - a(result.size()).shouldBeEqual(2); - a(result.get("id")).shouldNotBeNull(); - a(result.get("randomNumber")).shouldNotBeNull(); - a(contentType()).shouldBeEqual("application/json"); - } - - - @Test - public void shouldRenderOneRecordWithJackson() { - //execute controller - request().get("jackson"); - //process result - System.out.println(responseContent()); - Map result = JsonHelper.toMap(responseContent()); - //test result - a(result.size()).shouldBeEqual(2); - a(result.get("id")).shouldNotBeNull(); - a(result.get("randomNumber")).shouldNotBeNull(); - a(contentType()).shouldBeEqual("application/json"); - } - - @Ignore - public void shouldRenderResponseOneMinute() { - long endMillis = System.currentTimeMillis() + 60*1000; - do { - request().get("index"); - responseContent(); - } while (System.currentTimeMillis() < endMillis); - } -} diff --git a/frameworks/Java/activeweb/src/test/java/app/controllers/FortunesControllerSpec.java b/frameworks/Java/activeweb/src/test/java/app/controllers/FortunesControllerSpec.java deleted file mode 100644 index de277b39514..00000000000 --- a/frameworks/Java/activeweb/src/test/java/app/controllers/FortunesControllerSpec.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package app.controllers; - -import org.javalite.activeweb.DBControllerSpec; -import org.junit.Ignore; -import org.junit.Test; - -/** - * @author Eric Nielsen - */ -public class FortunesControllerSpec extends DBControllerSpec { - - @Test - public void shouldRenderHtml() { - request().integrateViews().get("index"); - System.out.print(responseContent()); - the(responseContent()).shouldContain( - "11<script>alert("This should not be displayed in a browser alert box.");</script>" - + "4A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1" - + "5A computer program does what you tell it to do, not what you want it to do." - + "2A computer scientist is someone who fixes things that aren't broken."); - } - - @Ignore - @Test - public void shouldRenderHtmlOneMinute() { - long endMillis = System.currentTimeMillis() + 60*1000; - do { - request().integrateViews().get("index"); - responseContent(); - } while (System.currentTimeMillis() < endMillis); - } -} diff --git a/frameworks/Java/activeweb/src/test/java/app/controllers/JsonControllerSpec.java b/frameworks/Java/activeweb/src/test/java/app/controllers/JsonControllerSpec.java deleted file mode 100644 index 720397d497f..00000000000 --- a/frameworks/Java/activeweb/src/test/java/app/controllers/JsonControllerSpec.java +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package app.controllers; - -import org.javalite.activeweb.ControllerSpec; -import org.junit.Ignore; -import org.junit.Test; - - -/** - * @author Igor Polevoy: 12/18/13 3:59 PM - * @author Eric Nielsen - */ -public class JsonControllerSpec extends ControllerSpec { - - @Test - public void shouldRenderMessage() { - request().integrateViews().get("index"); - the(responseContent()).shouldBeEqual("{\"message\":\"Hello, World!\"}"); - the(contentType()).shouldBeEqual("application/json"); - } - - @Test - public void shouldRenderMessageWithJackson() { - request().get("jackson"); - the(responseContent()).shouldBeEqual("{\"message\":\"Hello, World!\"}"); - the(contentType()).shouldBeEqual("application/json"); - } - - @Ignore - @Test - public void shouldRenderMessageOneMinute() { - long endMillis = System.currentTimeMillis() + 60*1000; - do { - request().integrateViews().get("index"); - responseContent(); - } while (System.currentTimeMillis() < endMillis); - } -} diff --git a/frameworks/Java/activeweb/src/test/java/app/controllers/JsonHelper.java b/frameworks/Java/activeweb/src/test/java/app/controllers/JsonHelper.java deleted file mode 100644 index 38052c5efd9..00000000000 --- a/frameworks/Java/activeweb/src/test/java/app/controllers/JsonHelper.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2009-2010 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * @author Igor Polevoy: 12/18/13 4:02 PM - */ - -package app.controllers; - - -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; -import java.util.Map; - -public class JsonHelper { - - public static Map toMap(String json) { - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(json, Map.class); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static Map[] toMaps(String json) { - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(json, Map[].class); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/frameworks/Java/activeweb/src/test/java/app/controllers/PlaintextControllerSpec.java b/frameworks/Java/activeweb/src/test/java/app/controllers/PlaintextControllerSpec.java deleted file mode 100644 index e3efb50e999..00000000000 --- a/frameworks/Java/activeweb/src/test/java/app/controllers/PlaintextControllerSpec.java +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2009-2015 Igor Polevoy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package app.controllers; - -import org.javalite.activeweb.ControllerSpec; -import org.junit.Ignore; -import org.junit.Test; - -/** - * @author Eric Nielsen - */ -public class PlaintextControllerSpec extends ControllerSpec { - - @Test - public void shouldRenderResponse() { - request().get("index"); - the(responseContent()).shouldBeEqual("Hello, World!"); - } - - @Ignore - public void shouldRenderHtmlOneMinute() { - long endMillis = System.currentTimeMillis() + 60*1000; - do { - request().get("index"); - responseContent(); - } while (System.currentTimeMillis() < endMillis); - } -} diff --git a/frameworks/Java/aio-socket/aio-socket.dockerfile b/frameworks/Java/aio-socket/aio-socket.dockerfile index 7aa11987383..8c012a22e3b 100644 --- a/frameworks/Java/aio-socket/aio-socket.dockerfile +++ b/frameworks/Java/aio-socket/aio-socket.dockerfile @@ -1,19 +1,13 @@ -FROM litongjava/maven:3.8.8-jdk8u391 AS builder +FROM maven:3-eclipse-temurin-25-alpine as maven WORKDIR /app - COPY pom.xml pom.xml -RUN mvn dependency:go-offline -q - COPY src src -RUN mvn package -Passembly -q -RUN ls -l && ls -l target - -FROM litongjava/jre:8u391-stable-slim +RUN mvn compile assembly:single -q +FROM amazoncorretto:25 WORKDIR /app - -COPY --from=builder /app/target/aio-socket-benchmark-1.0-jar-with-dependencies.jar /app/aio-socket-benchmark-1.0.jar +COPY --from=maven /app/target/aio-socket-benchmark-1.0-jar-with-dependencies.jar /app/app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC","-cp", "/app/aio-socket-benchmark-1.0.jar","com.litongjava.aio.http.server.HttpServer"] \ No newline at end of file +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/aio-socket/benchmark_config.json b/frameworks/Java/aio-socket/benchmark_config.json index 135582cd342..534c2815f14 100644 --- a/frameworks/Java/aio-socket/benchmark_config.json +++ b/frameworks/Java/aio-socket/benchmark_config.json @@ -5,7 +5,7 @@ "plaintext_url": "/plaintext", "json_url": "/json", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Micro", "framework": "aio-socket", "language": "Java", diff --git a/frameworks/Java/aio-socket/pom.xml b/frameworks/Java/aio-socket/pom.xml index 2b5dacefe65..6c0d8d6f3c4 100644 --- a/frameworks/Java/aio-socket/pom.xml +++ b/frameworks/Java/aio-socket/pom.xml @@ -1,90 +1,97 @@ - - 4.0.0 - com.litongjava - aio-socket-benchmark - 1.0 - ${project.artifactId} - - UTF-8 - 1.8 - ${java.version} - ${java.version} - com.litongjava.aio.http.server.HttpServer - - - - com.litongjava - aio-socket - 1.0.1 - - - com.alibaba - fastjson - 2.0.39 - + + 4.0.0 + com.litongjava + aio-socket-benchmark + 1.0 + ${project.artifactId} + + UTF-8 + 25 + ${java.version} + ${java.version} + com.litongjava.aio.http.server.HttpServer + + + + com.litongjava + aio-socket + 1.0.7 + + + com.alibaba.fastjson2 + fastjson2 + 2.0.60 + compile + - - - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - - - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - - - - - true - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - false - - - - - maven-assembly-plugin - 3.1.0 - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - + + + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + true + org.apache.maven.plugins + maven-compiler-plugin + 3.14.1 + + false + 25 + 25 + + + + maven-assembly-plugin + 3.1.0 + + + + com.litongjava.aio.http.server.HttpServer + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java index fa954b4cef4..ac2da6042a8 100644 --- a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java @@ -12,9 +12,8 @@ import java.time.ZoneId; import java.util.concurrent.ThreadFactory; -import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson2.JSON; import com.litongjava.aio.http.server.model.Message; -import com.litongjava.enhance.buffer.BufferPage; import com.litongjava.enhance.buffer.BufferPagePool; import com.litongjava.enhance.buffer.VirtualBuffer; import com.litongjava.enhance.channel.EnhanceAsynchronousChannelProvider; @@ -22,148 +21,162 @@ public class HttpServer { - private static int cpuNum = Runtime.getRuntime().availableProcessors(); - private static BufferPagePool pool = new BufferPagePool(0, 1024 * cpuNum, true); - private static BufferPage bufferPage = pool.allocateBufferPage(); - private static final String HELLO_WORLD = "Hello, World!"; - - public static void main(String[] args) throws Exception { - - // 创建异步通道提供者 - EnhanceAsynchronousChannelProvider provider = new EnhanceAsynchronousChannelProvider(false); - - // 创建通道组 - AsynchronousChannelGroup group = provider.openAsynchronousChannelGroup(2, new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - return new Thread(r, "http-server-thread"); - } - }); - - // 创建服务器通道并绑定端口 - EnhanceAsynchronousServerSocketChannel server = (EnhanceAsynchronousServerSocketChannel) provider.openAsynchronousServerSocketChannel(group); - server.bind(new InetSocketAddress(8080), 0); - - System.out.println("HTTP Server 正在监听端口 8080 ..."); - - // 异步接受连接 - server.accept(null, new CompletionHandler() { - @Override - public void completed(AsynchronousSocketChannel channel, Object attachment) { - // 继续接收其他连接 - server.accept(null, this); - handleClient(channel); - } - - @Override - public void failed(Throwable exc, Object attachment) { - exc.printStackTrace(); - } - }); - - // 主线程阻塞 - Thread.currentThread().join(); - } - - private static void handleClient(AsynchronousSocketChannel channel) { - VirtualBuffer virtualBuffer = bufferPage.allocate(8192); - ByteBuffer buffer = virtualBuffer.buffer(); - - channel.read(buffer, virtualBuffer, new CompletionHandler() { - @Override - public void completed(Integer result, VirtualBuffer attachment) { - try { - if (result > 0) { - buffer.flip(); - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - String request = new String(bytes, StandardCharsets.UTF_8); - - // 生成当前时间,格式为 RFC 1123 格式 - String date = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneId.of("GMT"))); - - ByteBuffer responseBuffer; - if (request.startsWith("GET /plaintext")) { - String body = "Hello, World!"; - String httpResponse = "HTTP/1.1 200 OK\r\n" + - "Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n" + - "Server: aio-socket\r\n" + - "Content-Type: text/plain\r\n" + - "Date: " + date + "\r\n" + - "\r\n" + - body; - responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); - - } else if (request.startsWith("GET /json")) { - String jsonString = JSON.toJSONString(new Message(HELLO_WORLD)); - int length = jsonString.getBytes(StandardCharsets.UTF_8).length; - String httpResponse = "HTTP/1.1 200 OK\r\n" + - "Content-Length: " + length + "\r\n" + - "Server: aio-socket\r\n" + - "Content-Type: application/json\r\n" + - "Date: " + date + "\r\n" + - "\r\n" + - jsonString; - responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); - } else { - String body = "Hello, World!"; - String httpResponse = "HTTP/1.1 200 OK\r\n" + - "Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n" + - "Content-Type: text/plain\r\n" + - "Date: " + date + "\r\n" + - "\r\n" + - body; - responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + private static BufferPagePool pool = new BufferPagePool(8192, true); + private static final String HELLO_WORLD = "Hello, World!"; + + public static void main(String[] args) throws Exception { + + // 创建异步通道提供者 + EnhanceAsynchronousServerSocketChannel server = getEnhanceAsynchronousServerSocketChannel(); + + System.out.println("HTTP Server 正在监听端口 8080 ..."); + + // 异步接受连接 + server.accept(null, new CompletionHandler() { + @Override + public void completed(AsynchronousSocketChannel channel, Object attachment) { + // 继续接收其他连接 + server.accept(null, this); + handleClient(channel); + } + + @Override + public void failed(Throwable exc, Object attachment) { + exc.printStackTrace(); } + }); - // 异步写响应 - channel.write(responseBuffer, attachment, new CompletionHandler() { - @Override - public void completed(Integer result, VirtualBuffer attachment) { + // 主线程阻塞 + Thread.currentThread().join(); + } + + private static EnhanceAsynchronousServerSocketChannel getEnhanceAsynchronousServerSocketChannel() throws IOException { + EnhanceAsynchronousChannelProvider provider = new EnhanceAsynchronousChannelProvider(false); + + // 创建通道组 + AsynchronousChannelGroup group = provider.openAsynchronousChannelGroup(2, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "http-server-thread"); + } + }); + + // 创建服务器通道并绑定端口 + EnhanceAsynchronousServerSocketChannel server = (EnhanceAsynchronousServerSocketChannel) provider.openAsynchronousServerSocketChannel(group); + server.bind(new InetSocketAddress(8080), 8192); + return server; + } + + private static void handleClient(AsynchronousSocketChannel channel) { + VirtualBuffer virtualBuf = pool.allocateSequentially(1024); + ByteBuffer buffer = virtualBuf.buffer(); + buffer.clear(); + + channel.read(buffer, virtualBuf, new CompletionHandler() { + @Override + public void completed(Integer result, VirtualBuffer attachment) { try { - channel.close(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - attachment.clean(); + if (result > 0) { + buffer.flip(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + String request = new String(bytes, StandardCharsets.UTF_8); + + // 生成当前时间,格式为 RFC 1123 格式 + String date = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneId.of("GMT"))); + + ByteBuffer responseBuffer; + if (request.startsWith("GET /plaintext")) { + String body = "Hello, World!"; + String httpResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n" + + "Content-Type: text/plain\r\n" + + "Server: aio-socket\r\n" + + "Date: " + date + "\r\n" + + "\r\n" + + body; + responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + + } else if (request.startsWith("GET /json")) { + String jsonString = JSON.toJSONString(new Message(HELLO_WORLD)); + int length = jsonString.getBytes(StandardCharsets.UTF_8).length; + String httpResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + length + "\r\n" + + "Server: aio-socket\r\n" + + "Content-Type: application/json\r\n" + + "Date: " + date + "\r\n" + + "\r\n" + + jsonString; + responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + } else { + String body = "Hello, World!"; + String httpResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n" + + "Content-Type: text/plain\r\n" + + "Date: " + date + "\r\n" + + "\r\n" + + body; + responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + } + + // 异步写响应 + channel.write(responseBuffer, attachment, new CompletionHandler() { + @Override + public void completed(Integer result, VirtualBuffer attachment) { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + attachment.clean(); + } + } + + @Override + public void failed(Throwable exc, VirtualBuffer attachment) { + exc.printStackTrace(); + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + attachment.clean(); + } + } + }); + } else { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + attachment.clean(); + } + } + } catch (Exception e) { + e.printStackTrace(); + try { + channel.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } finally { + attachment.clean(); + } } - } + } - @Override - public void failed(Throwable exc, VirtualBuffer attachment) { + @Override + public void failed(Throwable exc, VirtualBuffer attachment) { exc.printStackTrace(); try { - channel.close(); + channel.close(); } catch (IOException e) { - e.printStackTrace(); + e.printStackTrace(); } finally { - attachment.clean(); + attachment.clean(); } - } - }); - } else { - try { - channel.close(); - } catch (IOException e) { - e.printStackTrace(); } - } - } finally { - // 注意:如果在写操作中已经归还了虚拟缓冲区,则不要重复释放 - } - } - - @Override - public void failed(Throwable exc, VirtualBuffer attachment) { - exc.printStackTrace(); - try { - channel.close(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - attachment.clean(); - } - } - }); - } + }); + } } + diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java deleted file mode 100644 index 76f56b22dc9..00000000000 --- a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.litongjava.aio.http.server.model; - -public final class Fortune { - - public Long id; - public String message; - - public Fortune() { - } - - public Fortune(Long id, String message) { - this.id = id; - this.message = message; - } - - public Long getId() { - return id; - } - - public String getMessage() { - return message; - } -} \ No newline at end of file diff --git a/frameworks/Java/baratine/README.md b/frameworks/Java/baratine/README.md deleted file mode 100644 index 6f1616520ce..00000000000 --- a/frameworks/Java/baratine/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Baratine Benchmarking Test - -This is the Baratine portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -### Plaintext Test - -* [Plaintext test source](src/main/java/testTechempowerBaratine/PlaintextService.java) - -### JSON Encoding Test - -* [JSON test source](src/main/java/testTechempowerBaratine/JsonService.java) - -## Software Versions - -* [Java OpenJDK 1.8](http://openjdk.java.net/) -* [Baratine 0.11.0](https://github.com/baratine/baratine) - -## Test URLs - -### Plaintext Test - - http://localhost:8080/plaintext - -### JSON Encoding Test - - http://localhost:8080/json \ No newline at end of file diff --git a/frameworks/Java/baratine/baratine.dockerfile b/frameworks/Java/baratine/baratine.dockerfile deleted file mode 100644 index c120f8750d5..00000000000 --- a/frameworks/Java/baratine/baratine.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.6.1-jdk-11-slim as maven -WORKDIR /baratine -COPY pom.xml pom.xml -COPY src src -RUN mvn package -q - -FROM openjdk:11.0.3-jdk-slim -WORKDIR /baratine -COPY --from=maven /baratine/target/testTechempowerBaratine-0.0.1-SNAPSHOT.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-jar", "app.jar", "tfb-database"] diff --git a/frameworks/Java/baratine/benchmark_config.json b/frameworks/Java/baratine/benchmark_config.json deleted file mode 100644 index ba383303e2e..00000000000 --- a/frameworks/Java/baratine/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "baratine", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Stripped", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Baratine", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Baratine", - "notes": "", - "versus": "baratine" - } - }] -} diff --git a/frameworks/Java/baratine/config.toml b/frameworks/Java/baratine/config.toml deleted file mode 100644 index 55e02fc20bf..00000000000 --- a/frameworks/Java/baratine/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "baratine" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Stripped" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Baratine" -webserver = "None" -versus = "baratine" diff --git a/frameworks/Java/baratine/pom.xml b/frameworks/Java/baratine/pom.xml deleted file mode 100644 index b9f5f35c55f..00000000000 --- a/frameworks/Java/baratine/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - 4.0.0 - - io.baratine - testTechempowerBaratine - 0.0.1-SNAPSHOT - jar - - testTechempowerBaratine - - - UTF-8 - 11 - 11 - - - - - io.baratine - baratine - 1.0.1 - - - - junit - junit - 4.13.1 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - false - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.3 - - - package - - shade - - - - - testTechempowerBaratine.Main - - - - - - - - - diff --git a/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/JsonService.java b/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/JsonService.java deleted file mode 100644 index 6556f6f429f..00000000000 --- a/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/JsonService.java +++ /dev/null @@ -1,24 +0,0 @@ -package testTechempowerBaratine; - -import io.baratine.service.Result; -import io.baratine.service.Service; -import io.baratine.web.Get; - -@Service -public class JsonService -{ - @Get("/json") - public void hello(Result result) - { - result.ok(new HelloWorld("Hello, World!")); - } - - public static class HelloWorld { - private String message; - - public HelloWorld(String msg) - { - this.message = msg; - } - } -} diff --git a/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/Main.java b/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/Main.java deleted file mode 100644 index 6fc29f5ddd7..00000000000 --- a/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/Main.java +++ /dev/null @@ -1,17 +0,0 @@ -package testTechempowerBaratine; - -import static io.baratine.web.Web.*; -import io.baratine.web.WebServer; - -public class Main -{ - public static void main(String[] args) - { - include(PlaintextService.class); - include(JsonService.class); - - WebServer server = start(); - - server.join(); - } -} diff --git a/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/PlaintextService.java b/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/PlaintextService.java deleted file mode 100644 index efef8fc604d..00000000000 --- a/frameworks/Java/baratine/src/main/java/testTechempowerBaratine/PlaintextService.java +++ /dev/null @@ -1,15 +0,0 @@ -package testTechempowerBaratine; - -import io.baratine.service.Result; -import io.baratine.service.Service; -import io.baratine.web.Get; - -@Service -public class PlaintextService -{ - @Get("/plaintext") - public void hello(Result result) - { - result.ok("Hello, World!"); - } -} diff --git a/frameworks/Java/blade/benchmark_config.json b/frameworks/Java/blade/benchmark_config.json index 04386368397..fb575fb443a 100644 --- a/frameworks/Java/blade/benchmark_config.json +++ b/frameworks/Java/blade/benchmark_config.json @@ -23,7 +23,7 @@ "database_os": "Linux", "display_name": "blade", "notes": "", - "versus": "blade" + "versus": "" } } ] diff --git a/frameworks/Java/dropwizard/benchmark_config.json b/frameworks/Java/dropwizard/benchmark_config.json index d1bc9bd8af2..c96405bb43a 100644 --- a/frameworks/Java/dropwizard/benchmark_config.json +++ b/frameworks/Java/dropwizard/benchmark_config.json @@ -40,9 +40,9 @@ "webserver": "Jetty", "os": "Linux", "database_os": "Linux", - "display_name": "Dropwizard", + "display_name": "Dropwizard mongodb", "notes": "dropwizard mongodb using mongojack", - "versus": "" + "versus": "dropwizard" }, "postgres": { "db_url": "/db", @@ -61,9 +61,9 @@ "webserver": "Jetty", "os": "Linux", "database_os": "Linux", - "display_name": "dropwizard", + "display_name": "dropwizard pg", "notes": "dropwizard PostgreSQL using hibernate", - "versus": "servlet-postgres-raw", + "versus": "dropwizard", "tags": [] }, "jdbi-postgres": { @@ -82,9 +82,9 @@ "webserver": "Jetty", "os": "Linux", "database_os": "Linux", - "display_name": "dropwizard", + "display_name": "dropwizard jdbi", "notes": "dropwizard PostgreSQL using jdbi", - "versus": "servlet-postgres-raw", + "versus": "dropwizard", "tags": ["broken"] } }] diff --git a/frameworks/Java/dropwizard/config.toml b/frameworks/Java/dropwizard/config.toml index f6ae654f84f..22b90384d26 100644 --- a/frameworks/Java/dropwizard/config.toml +++ b/frameworks/Java/dropwizard/config.toml @@ -30,7 +30,7 @@ os = "Linux" orm = "Full" platform = "JAX-RS" webserver = "Jetty" -versus = "" +versus = "dropwizard" [postgres] urls.db = "/db" @@ -45,7 +45,7 @@ os = "Linux" orm = "Full" platform = "JAX-RS" webserver = "Jetty" -versus = "servlet-postgres-raw" +versus = "dropwizard" [jdbi-postgres] urls.db = "/db" @@ -60,4 +60,4 @@ os = "Linux" orm = "micro" platform = "JAX-RS" webserver = "Jetty" -versus = "servlet-postgres-raw" +versus = "dropwizard" diff --git a/frameworks/Java/edap-http/benchmark_config.json b/frameworks/Java/edap-http/benchmark_config.json index b82b5c11521..9ba2323f607 100755 --- a/frameworks/Java/edap-http/benchmark_config.json +++ b/frameworks/Java/edap-http/benchmark_config.json @@ -19,7 +19,7 @@ "database_os": "Linux", "display_name": "edap-http", "notes": "", - "versus": "edap-http" + "versus": "" }, "fast":{ "plaintext_url": "/plaintext", diff --git a/frameworks/Java/edap-http/config.toml b/frameworks/Java/edap-http/config.toml index d7fce281370..69ac9544c8a 100644 --- a/frameworks/Java/edap-http/config.toml +++ b/frameworks/Java/edap-http/config.toml @@ -12,7 +12,7 @@ os = "Linux" orm = "Raw" platform = "edap" webserver = "None" -versus = "edap-http" +versus = "" [http-fast] urls.plaintext = "/plaintext" diff --git a/frameworks/Java/edap-http/pom.xml b/frameworks/Java/edap-http/pom.xml index 65b9af2fa54..e5aafc34cd8 100644 --- a/frameworks/Java/edap-http/pom.xml +++ b/frameworks/Java/edap-http/pom.xml @@ -15,7 +15,7 @@ 21 21 21 - 0.1-SNAPSHOT + 0.1.1-SNAPSHOT edap diff --git a/frameworks/Java/edap-http/src/main/java/io/edap/http/Bootstrap.java b/frameworks/Java/edap-http/src/main/java/io/edap/http/Bootstrap.java index 74c331be93d..9e65f52cb00 100644 --- a/frameworks/Java/edap-http/src/main/java/io/edap/http/Bootstrap.java +++ b/frameworks/Java/edap-http/src/main/java/io/edap/http/Bootstrap.java @@ -4,6 +4,10 @@ import io.edap.Edap; import io.edap.http.server.HttpServer; import io.edap.http.server.HttpServerBuilder; +import io.edap.json.Eson; +import io.edap.json.JsonCodecRegister; +import io.edap.json.JsonEncoder; +import io.edap.json.JsonWriter; import java.io.IOException; @@ -14,18 +18,34 @@ public class Bootstrap { static final byte[] PLAIN_TEXT_CONTENT = "Hello, World!".getBytes(); + static JsonEncoder ENCODER = JsonCodecRegister.instance().getEncoder(Message.class); + public static void main(String[] args) throws IOException { HttpHandleOption option = new HttpHandleOption(); + HttpHandleOption optionPiplining = new HttpHandleOption(); String lazyParseHeaderStr = System.getProperty("lazyParseHeader", "false"); if (Boolean.parseBoolean(lazyParseHeaderStr)) { option.setLazyParseHeader(true); + optionPiplining.setLazyParseHeader(true); } + + final Message msg = new Message("Hello, World!"); + + //optionPiplining.setEnablePipelining(true); + HttpServer httpServer = new HttpServerBuilder() .listen(8080) .req("/plaintext", (req, resp) -> - resp.contentType(PLAIN).write(PLAIN_TEXT_CONTENT), option) + resp.contentType(PLAIN).write(PLAIN_TEXT_CONTENT), optionPiplining) .get("/json", (req, resp) -> { - resp.contentType(JSON).write(new Message("Hello, World!")); + JsonWriter writer = Eson.THREAD_WRITER.get(); + try { + writer.reset(); + ENCODER.encode(writer, msg); + resp.contentType(JSON).write(writer); + } catch (Exception e) { + throw new RuntimeException(e); + } }, option) .build(); Edap edap = new Edap(); diff --git a/frameworks/Java/firenio/benchmark_config.json b/frameworks/Java/firenio/benchmark_config.json index 0a0137ffc8a..790be28e5a3 100644 --- a/frameworks/Java/firenio/benchmark_config.json +++ b/frameworks/Java/firenio/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "firenio", "notes": "", - "versus": "firenio" + "versus": "" }, "http-lite": { "json_url": "/json", diff --git a/frameworks/Java/firenio/config.toml b/frameworks/Java/firenio/config.toml index 33d7b8ee28c..ba01d2eb775 100644 --- a/frameworks/Java/firenio/config.toml +++ b/frameworks/Java/firenio/config.toml @@ -12,7 +12,7 @@ os = "Linux" orm = "None" platform = "firenio" webserver = "None" -versus = "firenio" +versus = "" [http-lite] urls.plaintext = "/plaintext" diff --git a/frameworks/Java/greenlightning/README.md b/frameworks/Java/greenlightning/README.md deleted file mode 100755 index 044c87a44a1..00000000000 --- a/frameworks/Java/greenlightning/README.md +++ /dev/null @@ -1,22 +0,0 @@ - -# GreenLightning Benchmarking Test -# NathanTippy@gmail.com - -### Test Type Implementation Source Code - -* [JSON](src/main/java/com/javanut/gl/benchmark) -* [PLAINTEXT](src/main/java/com/javanut/gl/benchmark) - -## Important Libraries -The tests were run with: -* [Example](https://github.com/nathantippy/GreenLightning/tree/master/slipstream) - -### Implemented benchmarks -- [x] JSON serialization -- [x] Single query -- [x] Multiple queries -- [x] Fortunes -- [x] Data updates -- [x] Plaintext - - diff --git a/frameworks/Java/greenlightning/benchmark_config.json b/frameworks/Java/greenlightning/benchmark_config.json deleted file mode 100755 index 7e55f276f0f..00000000000 --- a/frameworks/Java/greenlightning/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "greenlightning", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "GreenLightning", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "GreenLightning", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Java/greenlightning/config.toml b/frameworks/Java/greenlightning/config.toml deleted file mode 100644 index f6ccfaa429d..00000000000 --- a/frameworks/Java/greenlightning/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "greenlightning" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/Java/greenlightning/greenlightning.dockerfile b/frameworks/Java/greenlightning/greenlightning.dockerfile deleted file mode 100644 index 2939bee8539..00000000000 --- a/frameworks/Java/greenlightning/greenlightning.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM maven:3.6.1-jdk-11 as maven - -WORKDIR /greenlightning -COPY pom.xml pom.xml -COPY src src - -RUN mvn clean install -q - -#COPY repo /usr/share/maven/ref/repository -#RUN mvn clean install -q -Dmaven.repo.local=/usr/share/maven/ref/repository - -FROM azul/zulu-openjdk-alpine:11.0.3 -WORKDIR /greenlightning -COPY --from=maven /greenlightning/target/greenlightning-test.jar app.jar - -EXPOSE 8080 - -CMD java -server -Xmx29g -XX:AutoBoxCacheMax=1000000 -XX:NewSize=64m -XX:+UseNUMA -jar app.jar diff --git a/frameworks/Java/greenlightning/pom.xml b/frameworks/Java/greenlightning/pom.xml deleted file mode 100644 index 9b48cc090e4..00000000000 --- a/frameworks/Java/greenlightning/pom.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - 4.0.0 - - com.javanut.gl.benchmark - benchmark-test - 1.1.14 - - - UTF-8 - - - - - com.javanut - greenlightning - ${project.version} - - - org.slf4j - slf4j-api - 1.7.25 - - - org.slf4j - slf4j-simple - 1.7.25 - runtime - - - junit - junit - 4.13.1 - jar - test - - - io.netty - netty-transport-native-epoll - 4.1.15.Final - linux-x86_64 - - - io.vertx - vertx-pg-client - 4.0.0-milestone3 - - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.4.1 - - -Xms1g - -Xmx1g - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.0 - - - compact2 - - 1.8 - 1.8 - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.5 - - -Xmx4g - - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - verify - - jar-no-fork - - - - - - - - maven-assembly-plugin - - - - com.javanut.gl.benchmark.GreenLightning - - - - jar-with-dependencies - - - greenlightning-test - false - - - - - - make-assembly - prepare-package - - single - - - - - - - - - - - diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/DBRest.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/DBRest.java deleted file mode 100644 index 517d93cb97a..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/DBRest.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.javanut.gl.benchmark; - -import com.javanut.gl.api.GreenRuntime; -import com.javanut.gl.api.HTTPRequestReader; -import com.javanut.gl.api.HTTPResponseService; -import com.javanut.gl.api.PubSubMethodListener; -import com.javanut.gl.api.RestMethodListener; -import com.javanut.gl.api.TickListener; - -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.sqlclient.PoolOptions; - -public class DBRest implements RestMethodListener, PubSubMethodListener, TickListener { - - private final ProcessUpdate processUpdate; - private final ProcessFortune processFortune; - private final ProcessQuery processQuery; - private static transient PoolManager pm; - - public DBRest(GreenRuntime runtime, PgConnectOptions options, PoolOptions poolOptions, int pipelineBits, - int maxResponseCount, int maxResponseSize) { - - pm = new PoolManager(options, poolOptions); - - HTTPResponseService service = runtime.newCommandChannel().newHTTPResponseService( - maxResponseCount, - maxResponseSize); - - processUpdate = new ProcessUpdate(pipelineBits, service, pm); - processFortune = new ProcessFortune(pipelineBits, service, pm); - processQuery = new ProcessQuery(pipelineBits, service, pm); - - } - - @Override - public void tickEvent() { - - processUpdate.tickEvent(); - processFortune.tickEvent(); - processQuery.tickEvent(); - - } - - public boolean restFortuneRequest(HTTPRequestReader request) { - return processFortune.restFortuneRequest(request); - } - - public boolean updateRestRequest(HTTPRequestReader request) { - return processUpdate.updateRestRequest(request); - } - - public boolean multiRestRequest(HTTPRequestReader request) { - return processQuery.multiRestRequest(request); - } - - public boolean singleRestRequest(HTTPRequestReader request) { - return processQuery.singleRestRequest(request); - } - - -} - diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Field.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Field.java deleted file mode 100644 index 49bdf2ae663..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Field.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.javanut.gl.benchmark; - -public enum Field { - //identifiers for each field used by routes and/or structures - CONNECTION, SEQUENCE, QUERIES; -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FortuneObject.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FortuneObject.java deleted file mode 100644 index 70b9b96a3f2..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FortuneObject.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.javanut.gl.benchmark; - -public class FortuneObject implements Comparable{ - - private int id; - private String fortune; - - public int getId() { - return id; - } - public void setId(int id) { - this.id = id; - } - public String getFortune() { - return fortune; - } - public void setFortune(String fortune) { - this.fortune = fortune; - } - - @Override - public int compareTo(FortuneObject o) { - return fortune.compareTo(o.fortune); - } - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FortunesObject.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FortunesObject.java deleted file mode 100644 index f3d4a050698..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FortunesObject.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.javanut.gl.benchmark; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -public class FortunesObject { - - private long connectionId; - private long sequenceId; - private int status; - private List list = new ArrayList(32); //non zero default - private List recycle = new ArrayList(32); - - public long getConnectionId() { - return connectionId; - } - - - public void setConnectionId(long connectionId) { - this.connectionId = connectionId; - } - - - public long getSequenceId() { - return sequenceId; - } - - - public void setSequenceId(long sequenceId) { - this.sequenceId = sequenceId; - } - - - public int getStatus() { - return status; - } - - - public void setStatus(int status) { - this.status = status; - } - - - public void clear() { - recycle.addAll(list); - list.clear(); - } - - public void sort() { - Collections.sort(list); - } - - public List list() { - return list; - } - - public void addFortune(int id, String fortune) { - - FortuneObject obj; //This eliminates any GC by recycling the old Fortune Objects to be repopulated with new data. - if (recycle.isEmpty()) { - obj = new FortuneObject(); - } else { - obj = recycle.remove(recycle.size()-1); - } - - obj.setId(id); - obj.setFortune(fortune); - list.add(obj); - - } - - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FrameworkTest.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FrameworkTest.java deleted file mode 100644 index caf6709ffee..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/FrameworkTest.java +++ /dev/null @@ -1,270 +0,0 @@ -package com.javanut.gl.benchmark; - -import java.util.concurrent.atomic.AtomicBoolean; - -import com.javanut.gl.api.GreenApp; -import com.javanut.gl.api.GreenCommandChannel; -import com.javanut.gl.api.GreenFramework; -import com.javanut.gl.api.GreenRuntime; -import com.javanut.pronghorn.network.ServerSocketWriterStage; - -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.PoolOptions; - - -public class FrameworkTest implements GreenApp { - - private final String payloadText; - final byte[] payload; - - private int bindPort; - private String host; - private int concurrentWritesPerChannel; - - private int telemetryPort; - private int minMemoryOfInputPipes; - private int dbCallMaxResponseSize; - private final int dbCallMaxResponseCount; - private int pipelineBits; - - private final int jsonMaxResponseCount; - private final int jsonMaxResponseSize; - - private PgConnectOptions options; - private PoolOptions poolOptions; - - private int maxQueueOut; - private int maxConnectionBits; - private int maxRequestSize; - - private int connectionsPerTrack; - private int connectionPort; - - - public AtomicBoolean foundDB = new AtomicBoolean(false); - public static String connectionHost = "localhost"; - public static String connectionDB = "testdb"; - public static String connectionUser = "postgres"; - public static String connectionPassword = "postgres"; - - //TODO: add utility to compute this based on need. - static final int c = 148;//293;//592; // to reach 16K simultaneous calls - - private final long defaultRate = Long.parseLong(System.getProperty("xx.rate", "120000")); //was 180000 - //Need to record how many records per pass are done... - - static { - System.setProperty("java.lang.Integer.IntegerCache.high", ""+Integer.MAX_VALUE); - - ServerSocketWriterStage.BASE_ADJUST = Float.parseFloat(System.getProperty("xx.ratio", "1")); - ServerSocketWriterStage.HARD_LIMIT_NS = Long.parseLong(System.getProperty("xx.limitns", "120000")); - } - - public FrameworkTest() { - - // use this in commit messages to narrow travis testing to just this project - // rebase before using this: [ci fw-only Java/greenlightning] - - - //this server works best with -XX:+UseNUMA - this(System.getProperty("host","0.0.0.0"), - Integer.parseInt(System.getProperty("port","8080")), //default port for test - c, //pipes per track - Integer.parseInt(System.getProperty("telemetry.port", "-1")), - "tfb-database", // jdbc:postgresql://tfb-database:5432/hello_world - "hello_world", - "benchmarkdbuser", - "benchmarkdbpass", - System.getProperty("custom.payload", "Hello, World!") - ); - - System.out.println("xx.rate "+defaultRate+" xx.ratio "+ServerSocketWriterStage.BASE_ADJUST+" xx.limitns "+ServerSocketWriterStage.HARD_LIMIT_NS); - - } - - public FrameworkTest(String host, int port, - int concurrentWritesPerChannel, - int telemetryPort, - String dbHost, - String dbName, - String dbUser, - String dbPass, - String payloadResponse) { - - this.payloadText = payloadResponse; - this.payload = payloadText.getBytes(); - - this.connectionsPerTrack = 2; - this.connectionPort = 5432; - this.bindPort = port; - this.host = host; - this.concurrentWritesPerChannel = concurrentWritesPerChannel; - - this.telemetryPort = telemetryPort; - this.pipelineBits = 15;//max concurrent in flight database requests 1<{ - foundDB.set(a.succeeded()); - if (null!=a.result()) { - a.result().close(); - } - }); - pool.close(); - - } catch (Throwable t) { - //t.printStackTrace(); - System.out.println("No database in use"); - } - - } - - - @Override - public void declareConfiguration(GreenFramework framework) { - - framework.setDefaultRate(defaultRate); - - //for 14 cores this is expected to use less than 16G, must use next largest prime to ensure smaller groups are not multiples. - framework.useHTTP1xServer(bindPort, this::parallelBehavior) //standard auto-scale - .setHost(host) - .setMaxConnectionBits(maxConnectionBits) - .setConcurrentChannelsPerDecryptUnit(concurrentWritesPerChannel) //16K 14 bits - - //NOTE: not sure this is optimal yet ... - //TODO: neeed to allow for multiple writes one pipe! big dif. - // .setConcurrentChannelsPerEncryptUnit(Math.max(1,concurrentWritesPerChannel/2)) //8K - .setConcurrentChannelsPerEncryptUnit(concurrentWritesPerChannel/25) ///80) ///16) // /8)//4) - - .setMaxRequestSize(maxRequestSize) - .setMaxQueueIn(c*16) - - .setMaxQueueOut(maxQueueOut) - .setMaxResponseSize(dbCallMaxResponseSize) //big enough for large mult db response - .useInsecureServer(); //turn off TLS - - framework.defineRoute() - .path("/plaintext") - .routeId(Struct.PLAINTEXT_ROUTE); - - framework.defineRoute() - .path("/json") - .routeId(Struct.JSON_ROUTE); - - framework.defineRoute() - .path("/db") - .routeId(Struct.DB_SINGLE_ROUTE); - - framework.defineRoute() - .path("/queries?queries=#{queries}") - .path("/queries") - .refineInteger("queries", Field.QUERIES, 1) - .routeId(Struct.DB_MULTI_ROUTE_INT); - - framework.defineRoute() - .path("/queries?queries=${queries}") - .routeId(Struct.DB_MULTI_ROUTE_TEXT); - - framework.defineRoute() - .path("/updates?queries=#{queries}") - .path("/updates") - .refineInteger("queries", Field.QUERIES, 1) - .routeId(Struct.UPDATES_ROUTE_INT); - - framework.defineRoute() - .path("/updates?queries=${queries}") - .routeId(Struct.UPDATES_ROUTE_TEXT); - - framework.defineRoute() - .path("/fortunes") - .routeId(Struct.FORTUNES_ROUTE); - - if (telemetryPort>0) { - framework.enableTelemetry(host,telemetryPort); - } else { - framework.enableTelemetryLogging(); - } - - framework.setTimerPulseRate(60 * 1000);//1x per minute - } - - - public void parallelBehavior(GreenRuntime runtime) { - - SimpleRest restTest = new SimpleRest(runtime, jsonMaxResponseCount, jsonMaxResponseSize, payload); - runtime.registerListener("Simple", restTest) - .includeRoutes(Struct.PLAINTEXT_ROUTE, restTest::plainRestRequest) - .includeRoutes(Struct.JSON_ROUTE, restTest::jsonRestRequest); - - DBRest dbRestInstance = new DBRest(runtime, options, poolOptions, pipelineBits, - dbCallMaxResponseCount, dbCallMaxResponseSize); - - runtime.registerListener("DBReadWrite", dbRestInstance) - .includeRoutes(Struct.DB_SINGLE_ROUTE, dbRestInstance::singleRestRequest) - .includeRoutes(Struct.DB_MULTI_ROUTE_TEXT, dbRestInstance::multiRestRequest) - .includeRoutes(Struct.DB_MULTI_ROUTE_INT, dbRestInstance::multiRestRequest) - .includeRoutes(Struct.UPDATES_ROUTE_TEXT, dbRestInstance::updateRestRequest) - .includeRoutes(Struct.UPDATES_ROUTE_INT, dbRestInstance::updateRestRequest) - .includeRoutes(Struct.FORTUNES_ROUTE, dbRestInstance::restFortuneRequest); - - } - - @Override - public void declareBehavior(GreenRuntime runtime) { - - //log the telemetry snapshot upon every pulse - final GreenCommandChannel cmd = runtime.newCommandChannel(); - runtime.addTimePulseListener("log",(t,i)->{ - cmd.logTelemetrySnapshot(); - }); - - } - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/GreenLightning.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/GreenLightning.java deleted file mode 100644 index 9445b326a59..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/GreenLightning.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.javanut.gl.benchmark; - -import com.javanut.gl.api.GreenRuntime; -import com.javanut.pronghorn.stage.scheduling.GraphManager; - -public class GreenLightning { - - public static void main(String[] args) { - //System.setProperty("pronghorn.processors", "28");//only for local testing, do not send to tech empower - - GraphManager.showThreadIdOnTelemetry = true; - GraphManager.showScheduledRateOnTelemetry = true; - GraphManager.showMessageCountRangeOnTelemetry = true; - - GreenRuntime.run(new FrameworkTest(),args); - - } - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/PoolManager.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/PoolManager.java deleted file mode 100644 index 4ae567916dc..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/PoolManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.javanut.gl.benchmark; - - -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.PoolOptions; - -public class PoolManager { - - private final transient PgConnectOptions options; - private transient PoolOptions poolOptions; - private PgPool pool; - private Vertx vertx; - - public PoolManager(PgConnectOptions options, PoolOptions poolOptions) { - this.options = options; - this.poolOptions = poolOptions; - - this.vertx = Vertx.vertx(new VertxOptions() - .setPreferNativeTransport(true) - .setWorkerPoolSize(4)//limit threads for this track - ); - - boolean usingNative = vertx.isNativeTransportEnabled(); - System.out.println("Running with native: " + usingNative); - } - - public PgPool pool() { - if (null==pool) { - pool = PgPool.pool(vertx, options, poolOptions); - } - return pool; - } - - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessFortune.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessFortune.java deleted file mode 100644 index 166d860e662..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessFortune.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.javanut.gl.benchmark; - -import com.javanut.gl.api.HTTPRequestReader; -import com.javanut.gl.api.HTTPResponseService; -import com.javanut.pronghorn.network.config.HTTPContentTypeDefaults; -import com.javanut.pronghorn.pipe.ObjectPipe; -import com.javanut.pronghorn.util.AppendableBuilder; - -import io.vertx.pgclient.PgPool; - - -public class ProcessFortune { - - private transient ObjectPipe fortuneInFlight; - private int htmlFortunePos=0; - private final transient AppendableBuilder htmlFortuneBuffer = new AppendableBuilder(); - private final transient PoolManager pm; - private final HTTPResponseService service; - - public ProcessFortune(int pipelineBits, HTTPResponseService service, PoolManager pm) { - - this.fortuneInFlight = new ObjectPipe(pipelineBits, FortunesObject.class, FortunesObject::new); - this.pm = pm; - this.service = service; - } - - private PgPool myPool = null; - - - public void tickEvent() { - - //for fortune - { - FortunesObject temp; - while (isReadyFortune(temp = fortuneInFlight.tailObject())) { - if (consumeResultObjectFortune(temp)) { - temp = fortuneInFlight.tailObject(); - } else { - break; - } - } - if (null==temp && myPool!=null) { //new test - //myPool.close(); - myPool = null; - } - } - - } - - - public boolean restFortuneRequest(HTTPRequestReader request) { - - final FortunesObject target = fortuneInFlight.headObject(); - if (null!=target) { - target.setConnectionId(request.getConnectionId()); - target.setSequenceId(request.getSequenceCode()); - - target.setStatus(-2);//out for work - target.clear(); - - if (null==myPool) { - myPool = pm.pool(); - } - - gatherData(target); - - fortuneInFlight.moveHeadForward(); //always move to ensure this can be read. - return true; - } else { - return false;//can not pick up new work now - } - } - - - //TODO: generate non DB version for tight local testing. - private void gatherData(final FortunesObject target) { - myPool.preparedQuery( "SELECT id, message FROM fortune", r -> { - //NOTE: we want to do as little work here a s possible since - // we want this thread to get back to work on other calls. - if (r.succeeded()) { - r.result().forEach((row)-> { - target.addFortune((Integer)row.getInteger(0), (String)row.getString(1)); - }); - target.setStatus(200); - } else { - System.out.println("fail: "+r.cause().getLocalizedMessage()); - target.setStatus(500); - } - - }); - } - - private boolean isReadyFortune(FortunesObject temp) { - return null!=temp && temp.getStatus()>=0; - } - - - - private boolean consumeResultObjectFortune(final FortunesObject t) { - - if (0 == htmlFortuneBuffer.byteLength()) { - //capture all the output text - t.addFortune(0, "Additional fortune added at request time."); - t.sort(); - Templates.fortuneTemplate.render(htmlFortuneBuffer, t); - htmlFortunePos = 0; - } - - - int bytesRemaining = htmlFortuneBuffer.byteLength() - htmlFortunePos; - int roomForWrite = service.maxVarLength(); - boolean hasContinuation = bytesRemaining >roomForWrite; - - //as long as htmlPos does not match the total bytes of the payload keep - //sending out continuation chunks. We do not know how many rows of fortunes - //may be in the database. - boolean ok; - if (0 == htmlFortunePos) { - - ok = service.publishHTTPResponse(t.getConnectionId(), t.getSequenceId(), 200, hasContinuation, - HTTPContentTypeDefaults.HTML, - w-> { - htmlFortunePos += htmlFortuneBuffer.copyTo(w, htmlFortunePos); - assert(hasContinuation == (htmlFortunePos!=htmlFortuneBuffer.byteLength())) : "internal error"; - - }); - } else { - ok =service.publishHTTPResponseContinuation(t.getConnectionId(), t.getSequenceId(), hasContinuation, - w-> { - htmlFortunePos += htmlFortuneBuffer.copyTo(w,htmlFortunePos); - assert(hasContinuation == (htmlFortunePos!=htmlFortuneBuffer.byteLength())) : "internal error"; - - }); - } - - if (ok) { - if (htmlFortunePos == htmlFortuneBuffer.byteLength()) { - - t.setStatus(-1); - fortuneInFlight.moveTailForward();//only move forward when it is consumed. - fortuneInFlight.publishTailPosition(); - t.list().clear(); - htmlFortuneBuffer.clear(); - return true;//do consume this since it is now fully sent - } else { - assert(htmlFortunePos < htmlFortuneBuffer.byteLength()) : "internal error"; - return false;//still have more to send later - } - } else { - return false; - } - - } - - - - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessQuery.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessQuery.java deleted file mode 100644 index 8639bbda4a7..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessQuery.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.javanut.gl.benchmark; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicBoolean; - -import com.javanut.gl.api.HTTPRequestReader; -import com.javanut.gl.api.HTTPResponseService; -import com.javanut.pronghorn.network.config.HTTPContentTypeDefaults; -import com.javanut.pronghorn.pipe.ObjectPipe; - -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.RowIterator; -import io.vertx.sqlclient.Tuple; - - -public class ProcessQuery { - - private final transient ObjectPipe DBRestInFlight; - private AtomicBoolean collectionPendingDBRest = new AtomicBoolean(false); - private transient final List collectorDBRest = new ArrayList(); - private final HTTPResponseService service; - private transient final PoolManager pm; - private final transient ThreadLocalRandom localRandom = ThreadLocalRandom.current(); - - public ProcessQuery(int pipelineBits, HTTPResponseService service, PoolManager pm) { - - - this.DBRestInFlight = new ObjectPipe(pipelineBits, ResultObject.class, ResultObject::new); - this.service = service; - this.pm = pm; - - - } - - public void tickEvent() { - //for DBRest - { - ResultObject temp; - while (isReadyDBRest(temp = DBRestInFlight.tailObject())) { - if (consumeResultObjectDBRest(temp)) { - temp = DBRestInFlight.tailObject(); - } else { - break; - } - } - } - - - } - - private int randomValue() { - return 1+localRandom.nextInt(10000); - } - - - public boolean multiRestRequest(HTTPRequestReader request) { - - final int queries; - if (Struct.DB_MULTI_ROUTE_INT == request.getRouteAssoc() ) { - queries = Math.min(Math.max(1, (request.structured().readInt(Field.QUERIES))),500); - } else { - queries = 1; - } - - - if (DBRestInFlight.hasRoomFor(queries)) { - - sendQueries(pm.pool(),queries,request.getConnectionId(),request.getSequenceCode()); - - return true; - } else { - return false; - } - } - - - private void sendQueries(PgPool p, int queries, long con, long seq) { - int q = queries; - - while (--q >= 0) { - - final ResultObject target = DBRestInFlight.headObject(); - - //already released but not published yet: TODO: we have a problem here!!! - assert(null!=target && -1==target.getStatus()) : "found status "+target.getStatus()+" on query "+q+" of "+queries ; //must block that this has been consumed?? should head/tail rsolve. - - target.setConnectionId(con); - target.setSequenceId(seq); - assert(target.getStatus()==-1);//waiting for work - target.setStatus(-2);//out for work - target.setGroupSize(queries); - - p.preparedQuery("SELECT * FROM world WHERE id=$1", Tuple.of(randomValue()), r -> { - if (r.succeeded()) { - - RowIterator resultSet = r.result().iterator(); - Tuple row = resultSet.next(); - - target.setId(row.getInteger(0)); - target.setResult(row.getInteger(1)); - target.setStatus(200); - - } else { - System.out.println("fail: "+r.cause().getLocalizedMessage()); - target.setStatus(500); - } - - }); - - DBRestInFlight.moveHeadForward(); //always move to ensure this can be read. - - } - } - - public boolean singleRestRequest(HTTPRequestReader request) { - - final ResultObject target = DBRestInFlight.headObject(); - - if (null!=target && -1==target.getStatus()) { - target.setConnectionId(request.getConnectionId()); - target.setSequenceId(request.getSequenceCode()); - assert(target.getStatus()==-1);//waiting for work - target.setStatus(-2);//out for work - target.setGroupSize(0);//do not put in a list so mark as 0. - - pm.pool().preparedQuery("SELECT * FROM world WHERE id=$1", Tuple.of(randomValue()), r -> { - if (r.succeeded()) { - - RowIterator resultSet = r.result().iterator(); - Row row = resultSet.next(); - - target.setId((Integer)row.getInteger(0)); - target.setResult((Integer)row.getInteger(1)); - target.setStatus(200); - - } else { - System.out.println("fail: "+r.cause().getLocalizedMessage()); - target.setStatus(500); - } - }); - - DBRestInFlight.moveHeadForward(); //always move to ensure this can be read. - return true; - } else { - return false;//can not pick up new work now - } - } - - - private boolean isReadyDBRest(ResultObject temp) { - - if (collectionPendingDBRest.get()) { - //now ready to send, we have all the data - ResultObject resultObject = collectorDBRest.get(0); - if (!publishMultiDBResponse(resultObject.getConnectionId(), - resultObject.getSequenceId() )) { - return false; - } - } - - return null!=temp && temp.getStatus()>=0; - } - - private boolean consumeResultObjectDBRest(final ResultObject t) { - boolean ok; - - /////////////////////////////// - if (0 == t.getGroupSize()) { - ok = service.publishHTTPResponse(t.getConnectionId(), t.getSequenceId(), 200, - HTTPContentTypeDefaults.JSON, - w-> { - Templates.singleTemplateDBRest.render(w, t); - t.setStatus(-1); - DBRestInFlight.moveTailForward();//only move forward when it is consumed. - DBRestInFlight.publishTailPosition(); - - }); - } else { - //collect all the objects - assert(isValidToAdd(t, collectorDBRest)); - collectorDBRest.add(t); - DBRestInFlight.moveTailForward(); - if (collectorDBRest.size() == t.getGroupSize()) { - //now ready to send, we have all the data - ok =publishMultiDBResponse(t.getConnectionId(), t.getSequenceId()); - - } else { - ok = true;//added to list - } - //moved forward so we can read next but write logic will still be blocked by state not -1 - - } - return ok; - } - - private boolean isValidToAdd(ResultObject t, List collector) { - if (collector.isEmpty()) { - return true; - } - if (collector.get(0).getSequenceId() != t.getSequenceId()) { - - System.out.println("show collection: "+showCollection(collector)); - System.out.println("new result adding con "+t.getConnectionId()+" seq "+t.getSequenceId()); - - }; - - - return true; - } - - private boolean publishMultiDBResponse(long conId, long seqCode) { - final boolean result = service.publishHTTPResponse(conId, seqCode, 200, - HTTPContentTypeDefaults.JSON, - w-> { - Templates.multiTemplateDBRest.render(w, collectorDBRest); - - int c = collectorDBRest.size(); - assert(collectorDBRest.get(0).getGroupSize()==c); - while (--c >= 0) { - assert(collectorDBRest.get(0).getGroupSize()==collectorDBRest.size()); - assert(collectorDBRest.get(c).getConnectionId() == conId) : c+" expected conId "+conId+" error: "+showCollection(collectorDBRest); - assert(collectorDBRest.get(c).getSequenceId() == seqCode) : c+" sequence error: "+showCollection(collectorDBRest); - collectorDBRest.get(c).setStatus(-1); - - } - collectorDBRest.clear(); - DBRestInFlight.publishTailPosition(); - }); - collectionPendingDBRest.set(!result); - return result; - } - - private String showCollection(List collector) { - - StringBuilder builder = new StringBuilder(); - builder.append("\n"); - int i = 0; - for(ResultObject ro: collector) { - builder.append(++i+" Con:"+ro.getConnectionId()).append(" Id:").append(ro.getId()).append(" Seq:").append(ro.getSequenceId()); - builder.append("\n"); - } - - - return builder.toString(); - } - - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessUpdate.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessUpdate.java deleted file mode 100644 index 17e396135bb..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ProcessUpdate.java +++ /dev/null @@ -1,315 +0,0 @@ -package com.javanut.gl.benchmark; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import com.javanut.gl.api.HTTPRequestReader; -import com.javanut.gl.api.HTTPResponseService; -import com.javanut.pronghorn.network.config.HTTPContentTypeDefaults; -import com.javanut.pronghorn.pipe.ObjectPipe; - -import io.vertx.core.AsyncResult; -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.PreparedQuery; -import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.RowIterator; -import io.vertx.sqlclient.RowSet; -import io.vertx.sqlclient.SqlConnection; -import io.vertx.sqlclient.Tuple; - - -public class ProcessUpdate { - - private transient ObjectPipe dbUpdateInFlight; - private final transient List collectorDBUpdate = new ArrayList(); - private final transient ThreadLocalRandom localRandom = ThreadLocalRandom.current(); - private final HTTPResponseService service; - private final transient PoolManager pm; - private final AtomicInteger requestsInFlight = new AtomicInteger(); - - private PreparedQuery selectQuery; - private boolean building = false; - private PreparedQuery updateQuery; - - public ProcessUpdate(int pipelineBits, HTTPResponseService service, PoolManager pm) { - this.dbUpdateInFlight = new ObjectPipe(pipelineBits, ResultObject.class, ResultObject::new); - this.service = service; - this.pm = pm; - selectableQuery(); - updateQuery(); - } - - - public void tickEvent() { - - ResultObject temp = dbUpdateInFlight.tailObject(); - while (null!=temp && temp.getStatus()>=0) { - consumeResultObjectDBUpdate(temp); - temp = dbUpdateInFlight.tailObject(); - } - - } - - - private int randomValue() { - return 1+localRandom.nextInt(10000); - } - - public boolean updateRestRequest(HTTPRequestReader request) { - int queries; - if (Struct.UPDATES_ROUTE_INT == request.getRouteAssoc() ) { - queries = Math.min(Math.max(1, (request.structured().readInt(Field.QUERIES))),500); - } else { - queries = 1; - } - long conId = request.getConnectionId(); - long seqCode = request.getSequenceCode(); - int temp = requestsInFlight.incrementAndGet(); - - if (dbUpdateInFlight.hasRoomFor(queries) && service.hasRoomFor(temp) ) { - - processConnection(queries, conId, seqCode); - - return true; - } else { - requestsInFlight.decrementAndGet(); - return false; - } - } - - - private PreparedQuery selectableQuery() { - - if (null!=selectQuery || building) { - return selectQuery; - } else { - building = true; - pm.pool().getConnection(h -> { - - if (h.succeeded()) { - SqlConnection connection = h.result(); - - connection.prepare("SELECT * FROM world WHERE id=$1", ph -> { - if (ph.succeeded()) { - selectQuery = ph.result(); - - building = false; - if (updateQuery==null) { - updateQuery(); - } - - } else { - ph.cause().printStackTrace(); - } - }); - - connection.close(); - } else { - h.cause().printStackTrace(); - } - }); - return null; - } - } - - private PreparedQuery updateQuery() { - - if (null!=updateQuery || building) { - return updateQuery; - } else { - building = true; - pm.pool().getConnection(h -> { - - if (h.succeeded()) { - SqlConnection connection = h.result(); - - connection.prepare("UPDATE world SET randomnumber=$1 WHERE id=$2", ph -> { - if (ph.succeeded()) { - updateQuery = ph.result(); - building = false; - if (selectQuery == null) { - selectableQuery(); - } - } - }); - - connection.close(); - } - - - }); - return null; - } - } - - - private void processConnection(int queries, long conId, long seqCode) { - - //only process after we have the prepared statements built. - PreparedQuery query = selectableQuery(); - if (query==null) { - return; - } - - PreparedQuery update= updateQuery(); - if (update==null) { - return; - } - - List objs = new ArrayList(queries); - int q = queries; - while (--q >= 0) { - processSingleUpdate(queries, conId, seqCode, objs, query, update); - - } - } - - - private void processSingleUpdate(int queries, long conId, long seqCode, - List objs, - PreparedQuery query, PreparedQuery update) { - //testing one per query - - final ResultObject worldObject = dbUpdateInFlight.headObject(); - assert(null!=worldObject); - - worldObject.setConnectionId(conId); - worldObject.setSequenceId(seqCode); - worldObject.setStatus(-2);//out for work - worldObject.setGroupSize(queries); - - worldObject.setId(randomValue()); - objs.add(worldObject); - - try { - query.execute(Tuple.of(worldObject.getId()), r -> { - if (r.succeeded()) { - - RowIterator resultSet = r.result().iterator(); - Tuple row = resultSet.next(); - - assert(worldObject.getId()==row.getInteger(0)); - - //read the existing random value and store it in the world object - worldObject.setResult(row.getInteger(1)); - /////////////////////////////////// - //the object can be used here with the old value - /////////////////////////////////// - //set the new random value in this object - worldObject.setResult(randomValue()); - - try { - update.execute( - Tuple.of(worldObject.getResult(), worldObject.getId()), ar -> { - setStatus(worldObject, ar); - } - ); - } catch (Throwable t) { - t.printStackTrace(); - this.updateQuery = null; //TODO: need to try again. - } - - } else { - - System.out.println("unable to query"); - if (r.cause()!=null) { - r.cause().printStackTrace(); - } - - worldObject.setStatus(500); - } - - //on all N responses..... - - }); - - dbUpdateInFlight.moveHeadForward(); //always move to ensure this can be read. - } catch (Throwable t) { - t.printStackTrace(); - this.selectQuery = null; - //TODO: rollabck?? - } - } - - - private static void setStatus(final ResultObject worldObject, AsyncResult> ar) { - if (ar.succeeded()) { - worldObject.setStatus(200); - - } else { - System.out.println("unable to update"); - if (ar.cause()!=null) { - ar.cause().printStackTrace(); - } - - worldObject.setStatus(500); - } - } - - -// private void execUpdate(List toUpdate, List args, int i) { -// -// pm.pool().preparedBatch("UPDATE world SET randomnumber=$1 WHERE id=$2", -// args, ar -> { -// -// pause.addAndGet(i); -// int status; -// if (ar.succeeded()) { -// status = 200; -// pause.decrementAndGet(); -// } else { -// execUpdate(toUpdate, args, 0); -// return; -//// System.out.println("unable to update"); -//// if (ar.cause()!=null) { -//// ar.cause().printStackTrace(); -//// } -//// status = 500; -// } -// toUpdate.forEach(w->{ -// w.setStatus(status); -// }); -// -// -// }); -// -// } - - private void consumeResultObjectDBUpdate(final ResultObject t) { - - //collect all the objects - collectorDBUpdate.add(t); - dbUpdateInFlight.moveTailForward();//only move forward when it is consumed. - if (collectorDBUpdate.size() == t.getGroupSize()) { - //now ready to send, we have all the data - publishMultiResponseDBUpdate(t.getConnectionId(), t.getSequenceId()); - } - } - - private void publishMultiResponseDBUpdate(long conId, long seqCode) { - boolean result = service.publishHTTPResponse(conId, seqCode, 200, - HTTPContentTypeDefaults.JSON, - w-> { - Templates.multiTemplate.render(w, collectorDBUpdate); - int c = collectorDBUpdate.size(); - while (--c>=0) { - assert(collectorDBUpdate.get(c).getConnectionId() == conId); - assert(collectorDBUpdate.get(c).getSequenceId() == seqCode); - collectorDBUpdate.get(c).setStatus(-1); - } - collectorDBUpdate.clear(); - dbUpdateInFlight.publishTailPosition(); - }); - assert(result) : "internal error, we should not pick up more work than we can send"; - requestsInFlight.decrementAndGet(); - } - - - - - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/RequestObject.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/RequestObject.java deleted file mode 100644 index f3dfbdd1bb9..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/RequestObject.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.javanut.gl.benchmark; - -import com.javanut.gl.api.HTTPRequestReader; -import com.javanut.pronghorn.pipe.StructuredReader; - -public class RequestObject { - - public RequestObject(HTTPRequestReader request) { - StructuredReader reader = request.structured(); - - } - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ResultObject.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ResultObject.java deleted file mode 100644 index 63353540790..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/ResultObject.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.javanut.gl.benchmark; - -import java.util.concurrent.atomic.AtomicInteger; - -public class ResultObject { - - private long connectionId; - private long sequenceId; - private AtomicInteger status = new AtomicInteger(); - private int id; - private int result; - private int groupSize; - - public int getGroupSize() { - return groupSize; - } - - - public void setGroupSize(int groupSize) { - this.groupSize = groupSize; - } - - - public long getConnectionId() { - return connectionId; - } - - - public void setConnectionId(long connectionId) { - this.connectionId = connectionId; - } - - - public long getSequenceId() { - return sequenceId; - } - - - public void setSequenceId(long sequenceId) { - this.sequenceId = sequenceId; - } - - - public int getStatus() { - return status.get(); - } - - - public void setStatus(int status) { - this.status.set(status); - } - - - public int getId() { - return id; - } - - - public void setId(int id) { - this.id = id; - } - - - public int getResult() { - return result; - } - - - public void setResult(int result) { - this.result = result; - } - - - public ResultObject(int id, int result) { - this.id = id; - this.result = result; - this.groupSize = 0; - this.status.set(-1); - } - - public ResultObject() { - this.status.set(-1); - this.groupSize = 0; - } - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/SimpleRest.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/SimpleRest.java deleted file mode 100644 index 4ce6a09ba24..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/SimpleRest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.javanut.gl.benchmark; - -import com.javanut.gl.api.GreenRuntime; -import com.javanut.gl.api.HTTPRequestReader; -import com.javanut.gl.api.HTTPResponseService; -import com.javanut.gl.api.RestMethodListener; -import com.javanut.json.encode.JSONRenderer; -import com.javanut.pronghorn.network.config.HTTPContentTypeDefaults; - -public class SimpleRest implements RestMethodListener { - - - private final byte[] messageBytes = "message".getBytes(); - private final byte[] payload; - private final HTTPResponseService responseService; - private final JSONRenderer renderJSON; - - public SimpleRest(GreenRuntime runtime, int maxResponseCount, int maxResponseSize, byte[] payload) { - this.payload = payload; - this.responseService = runtime - .newCommandChannel() - .newHTTPResponseService(maxResponseCount, maxResponseSize); - - this.renderJSON = new JSONRenderer() - .startObject() - .string(messageBytes, (o,t) -> t.write(payload) ) - .endObject(); - - } - - - - public boolean jsonRestRequest(HTTPRequestReader request) { - - //this check is to postpone the work if the network has become saturated - if (responseService.hasRoomFor(1)) { - - return responseService.publishHTTPResponse(request, - HTTPContentTypeDefaults.JSON, - w -> renderJSON.render(w,new RequestObject(request)) - ); - } else { - return false; - } - } - - - public boolean plainRestRequest(HTTPRequestReader request) { - - return responseService.publishHTTPResponse(request, - HTTPContentTypeDefaults.PLAIN, - w -> w.write(payload) - ); - - } - -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Struct.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Struct.java deleted file mode 100644 index dad641ec5b3..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Struct.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.javanut.gl.benchmark; - -public enum Struct { - PLAINTEXT_ROUTE, JSON_ROUTE, - DB_SINGLE_ROUTE, - DB_MULTI_ROUTE_INT, DB_MULTI_ROUTE_TEXT, - FORTUNES_ROUTE, - UPDATES_ROUTE_INT, UPDATES_ROUTE_TEXT; -} diff --git a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Templates.java b/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Templates.java deleted file mode 100644 index 47e11197790..00000000000 --- a/frameworks/Java/greenlightning/src/main/java/com/javanut/gl/benchmark/Templates.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.javanut.gl.benchmark; - -import java.util.List; - -import com.javanut.json.encode.JSONRenderer; -import com.javanut.pronghorn.util.Appendables; -import com.javanut.pronghorn.util.template.StringTemplateBuilder; -import com.javanut.pronghorn.util.template.StringTemplateRenderer; - -public class Templates { - - static final byte[] ROW_FINISH = "\n".getBytes(); - static final byte[] ROW_MIDDLE = "".getBytes(); - static final byte[] ROW_START = "".getBytes(); - - static final transient StringTemplateRenderer fortuneTemplate = - new StringTemplateBuilder() - .add(" Fortunes \n") - .add((t,s,i)-> { - if (i") - .finish(); - - //////////////////////////////////// - //////////////////////////////////// - - static final JSONRenderer> multiTemplate = new JSONRenderer>() - .array((o,i) -> i o.get(i)) - .integer("id", o -> o.getId() ) - .integer("randomNumber", o -> o.getResult()) - .endObject(); - - //////////////////////////////////// - //////////////////////////////////// - - static final JSONRenderer> multiTemplateDBRest = new JSONRenderer>() - .array((o,i) -> i o.get(i)) - .integer("id", o -> o.getId() ) - .integer("randomNumber", o -> o.getResult()) - .endObject(); - //////////////////////////////////// - //////////////////////////////////// - - static final JSONRenderer singleTemplateDBRest = new JSONRenderer() - .startObject() - .integer("id", o -> o.getId() ) - .integer("randomNumber", o -> o.getResult()) - .endObject(); - -} diff --git a/frameworks/Java/greenlightning/src/main/resources/GreenLight.props b/frameworks/Java/greenlightning/src/main/resources/GreenLight.props deleted file mode 100644 index d3894e4859a..00000000000 --- a/frameworks/Java/greenlightning/src/main/resources/GreenLight.props +++ /dev/null @@ -1 +0,0 @@ -main=com.javanut.gl.benchmark.FrameworkTest \ No newline at end of file diff --git a/frameworks/Java/grizzly/benchmark_config.json b/frameworks/Java/grizzly/benchmark_config.json index 50022cee8a6..f16724e670c 100644 --- a/frameworks/Java/grizzly/benchmark_config.json +++ b/frameworks/Java/grizzly/benchmark_config.json @@ -39,9 +39,9 @@ "webserver": "Grizzly", "os": "Linux", "database_os": "Linux", - "display_name": "grizzly", + "display_name": "grizzly-jersey", "notes": "", - "versus": "" + "versus": "grizzly" } }] } diff --git a/frameworks/Java/grizzly/config.toml b/frameworks/Java/grizzly/config.toml index 8a5bd878187..4cff3377e0b 100644 --- a/frameworks/Java/grizzly/config.toml +++ b/frameworks/Java/grizzly/config.toml @@ -29,4 +29,4 @@ os = "Linux" orm = "Full" platform = "JAX-RS" webserver = "Grizzly" -versus = "" +versus = "grizzly" diff --git a/frameworks/Java/helidon/helidon-nima.dockerfile b/frameworks/Java/helidon/helidon-nima.dockerfile index 25278db67a9..bd67a0d325a 100644 --- a/frameworks/Java/helidon/helidon-nima.dockerfile +++ b/frameworks/Java/helidon/helidon-nima.dockerfile @@ -4,7 +4,7 @@ COPY nima/src src COPY nima/pom.xml pom.xml RUN mvn package -q -FROM openjdk:25-jdk-slim +FROM openjdk:25-ea-jdk WORKDIR /helidon COPY --from=maven /helidon/target/libs libs COPY --from=maven /helidon/target/benchmark-nima.jar app.jar diff --git a/frameworks/Java/helidon/helidon.dockerfile b/frameworks/Java/helidon/helidon.dockerfile index f1cc3c8f4e7..ec0aad92dc6 100644 --- a/frameworks/Java/helidon/helidon.dockerfile +++ b/frameworks/Java/helidon/helidon.dockerfile @@ -4,7 +4,7 @@ COPY reactive/src src COPY reactive/pom.xml pom.xml RUN mvn package -q -FROM openjdk:19-jdk-slim +FROM openjdk:19-ea-jdk WORKDIR /helidon COPY --from=maven /helidon/target/libs libs COPY --from=maven /helidon/target/benchmark-reactive.jar app.jar diff --git a/frameworks/Java/helidon/nima/pom.xml b/frameworks/Java/helidon/nima/pom.xml index 0d312c8eed8..9bb56c9712c 100644 --- a/frameworks/Java/helidon/nima/pom.xml +++ b/frameworks/Java/helidon/nima/pom.xml @@ -37,6 +37,7 @@ 3.11.0 1.3.0 4.5.3 + 2.1 0.9.23 3.1.15 @@ -68,6 +69,11 @@ vertx-pg-client ${vertx-pg-client.version} + + com.ongres.scram + client + ${ongres-scram.version} + com.zaxxer HikariCP diff --git a/frameworks/Java/helidon/reactive/pom.xml b/frameworks/Java/helidon/reactive/pom.xml index e3f862db330..5e07c75b9e9 100644 --- a/frameworks/Java/helidon/reactive/pom.xml +++ b/frameworks/Java/helidon/reactive/pom.xml @@ -35,7 +35,8 @@ 19 3.8.1 1.3.0 - 4.2.0 + 4.5.3 + 2.1 @@ -56,6 +57,11 @@ vertx-pg-client ${vertx-pg-client.version} + + com.ongres.scram + client + ${ongres-scram.version} + com.fizzed rocker-runtime diff --git a/frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java b/frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java index 94b2332612d..87fa84fabc5 100644 --- a/frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java +++ b/frameworks/Java/helidon/reactive/src/main/java/io/helidon/benchmark/reactive/services/FortuneService.java @@ -16,8 +16,6 @@ public class FortuneService implements Service, Handler { - private static final Fortune ADDITIONAL_FORTUNE = new Fortune(0, "Additional fortune added at request time."); - private final DbRepository repository; public FortuneService(DbRepository repository) { @@ -34,7 +32,7 @@ public void accept(ServerRequest req, ServerResponse res) { res.headers().contentType(MediaType.TEXT_HTML.withCharset(StandardCharsets.UTF_8.name())); repository.getFortunes() .forSingle(fortuneList -> { - fortuneList.add(ADDITIONAL_FORTUNE); + fortuneList.add(new Fortune(0, "Additional fortune added at request time.")); fortuneList.sort(Comparator.comparing(Fortune::getMessage)); res.headers().contentType(MediaType.TEXT_HTML.withCharset(StandardCharsets.UTF_8.name())); res.send(fortunes.template(fortuneList) diff --git a/frameworks/Java/hserver-business/benchmark_config.json b/frameworks/Java/hserver-business/benchmark_config.json index bd9e4a47600..8b6dafa6a61 100644 --- a/frameworks/Java/hserver-business/benchmark_config.json +++ b/frameworks/Java/hserver-business/benchmark_config.json @@ -24,7 +24,7 @@ "database_os": "Linux", "display_name": "hserver-business", "notes": "", - "versus": "hserver-business" + "versus": "hserver" } } ] diff --git a/frameworks/Java/hserver-business/config.toml b/frameworks/Java/hserver-business/config.toml index ef213a045ff..9c6cd7747d3 100644 --- a/frameworks/Java/hserver-business/config.toml +++ b/frameworks/Java/hserver-business/config.toml @@ -14,4 +14,4 @@ os = "Linux" orm = "Full" platform = "hserver-business" webserver = "hserver-business" -versus = "hserver-business" +versus = "hserver" diff --git a/frameworks/Java/hserver/benchmark_config.json b/frameworks/Java/hserver/benchmark_config.json index 035eae68c9c..8b5a5130e8c 100644 --- a/frameworks/Java/hserver/benchmark_config.json +++ b/frameworks/Java/hserver/benchmark_config.json @@ -24,7 +24,7 @@ "database_os": "Linux", "display_name": "hserver", "notes": "", - "versus": "hserver" + "versus": "" } } ] diff --git a/frameworks/Java/hserver/config.toml b/frameworks/Java/hserver/config.toml index 6979faa03a0..3c93e5e831c 100644 --- a/frameworks/Java/hserver/config.toml +++ b/frameworks/Java/hserver/config.toml @@ -14,4 +14,4 @@ os = "Linux" orm = "Full" platform = "hserver" webserver = "hserver" -versus = "hserver" +versus = "" diff --git a/frameworks/Java/httpserver/benchmark_config.json b/frameworks/Java/httpserver/benchmark_config.json index 16e9cdab907..1b9a423d38d 100755 --- a/frameworks/Java/httpserver/benchmark_config.json +++ b/frameworks/Java/httpserver/benchmark_config.json @@ -4,11 +4,12 @@ { "default": { "json_url": "/json", + "fortune_url": "/fortunes", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "None", + "database": "postgres", "framework": "None", "language": "Java", "flavor": "None", @@ -21,31 +22,14 @@ "notes": "", "versus": "" }, - "postgres": { - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "None", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "httpserver", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "httpserver-postgres", - "notes": "", - "versus": "" - }, "graalvm": { "json_url": "/json", + "fortune_url": "/fortunes", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "None", + "database": "postgres", "framework": "None", "language": "Java", "flavor": "None", @@ -60,11 +44,12 @@ }, "robaho": { "json_url": "/json", + "fortune_url": "/fortunes", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "None", + "database": "postgres", "framework": "None", "language": "Java", "flavor": "None", @@ -77,12 +62,14 @@ "notes": "", "versus": "" }, - "robaho-postgres": { + "robaho-zgc": { + "json_url": "/json", "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "Postgres", + "database": "postgres", "framework": "None", "language": "Java", "flavor": "None", @@ -91,17 +78,18 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "httpserver-robaho-postgres", + "display_name": "httpserver-robaho-zgc", "notes": "", - "versus": "" + "versus": "httpserver-robaho" }, "robaho-graalvm": { "json_url": "/json", + "fortune_url": "/fortunes", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "None", + "database": "postgres", "framework": "None", "language": "Java", "flavor": "None", diff --git a/frameworks/Java/httpserver/config.toml b/frameworks/Java/httpserver/config.toml index 3531b9e5e9f..c9c0c0e11e6 100644 --- a/frameworks/Java/httpserver/config.toml +++ b/frameworks/Java/httpserver/config.toml @@ -3,22 +3,11 @@ name = "httpserver" [main] urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "httpserver" -webserver = "None" -versus = "" - -[postgres] urls.fortune = "/fortunes" +urls.json = "/json" approach = "Realistic" classification = "Platform" -database = "Postgres" +database = "postgres" database_os = "Linux" os = "Linux" orm = "Raw" @@ -26,13 +15,13 @@ platform = "httpserver" webserver = "None" versus = "" - [graalvm] urls.plaintext = "/plaintext" +urls.fortune = "/fortunes" urls.json = "/json" approach = "Realistic" classification = "Platform" -database = "None" +database = "postgres" database_os = "Linux" os = "Linux" orm = "Raw" @@ -43,10 +32,11 @@ versus = "httpserver" [robaho] urls.plaintext = "/plaintext" +urls.fortune = "/fortunes" urls.json = "/json" approach = "Realistic" classification = "Platform" -database = "None" +database = "postgres" database_os = "Linux" os = "Linux" orm = "Raw" @@ -55,25 +45,27 @@ webserver = "None" versus = "httpserver" -[robaho-postgres] +[robaho-graalvm] +urls.plaintext = "/plaintext" urls.fortune = "/fortunes" +urls.json = "/json" approach = "Realistic" classification = "Platform" -database = "Postgres" +database = "postgres" database_os = "Linux" os = "Linux" orm = "Raw" platform = "httpserver" webserver = "None" -versus = "" - +versus = "httpserver-robaho" -[robaho-graalvm] +[robaho-zgc] urls.plaintext = "/plaintext" +urls.fortune = "/fortunes" urls.json = "/json" approach = "Realistic" classification = "Platform" -database = "None" +database = "postgres" database_os = "Linux" os = "Linux" orm = "Raw" diff --git a/frameworks/Java/httpserver/httpserver-graalvm.dockerfile b/frameworks/Java/httpserver/httpserver-graalvm.dockerfile index 9af2d5f4026..1290d9ac94f 100644 --- a/frameworks/Java/httpserver/httpserver-graalvm.dockerfile +++ b/frameworks/Java/httpserver/httpserver-graalvm.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar ap EXPOSE 8080 -CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dsun.net.httpserver.nodelay=true", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-postgres.dockerfile deleted file mode 100644 index 6856f3431fa..00000000000 --- a/frameworks/Java/httpserver/httpserver-postgres.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3-eclipse-temurin-25-alpine as maven -WORKDIR /httpserver -COPY pom.xml pom.xml -COPY src src -RUN mvn compile assembly:single -q - -FROM amazoncorretto:25 -WORKDIR /httpserver -COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar", "postgres"] diff --git a/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile index f6646e3095e..8860a71d0bd 100644 --- a/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho-graalvm.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies EXPOSE 8080 -CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-Drobaho.net.httpserver.nodelay=true", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile deleted file mode 100644 index 0b99cb7fe41..00000000000 --- a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3-eclipse-temurin-25-alpine as maven -WORKDIR /httpserver-robaho -COPY pom.xml pom.xml -COPY src src -RUN mvn compile -P robaho assembly:single -q - -FROM amazoncorretto:25 -WORKDIR /httpserver-robaho -COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-jar", "app.jar", "postgres"] diff --git a/frameworks/Java/httpserver/httpserver-robaho-zgc.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-zgc.dockerfile new file mode 100644 index 00000000000..5363d93850b --- /dev/null +++ b/frameworks/Java/httpserver/httpserver-robaho-zgc.dockerfile @@ -0,0 +1,13 @@ +FROM maven:3-eclipse-temurin-25-alpine as maven +WORKDIR /httpserver-robaho +COPY pom.xml pom.xml +COPY src src +RUN mvn compile -P robaho assembly:single -q + +FROM amazoncorretto:25 +WORKDIR /httpserver-robaho +COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseZGC", "-XX:MaxRAMPercentage=70", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar"] \ No newline at end of file diff --git a/frameworks/Java/httpserver/httpserver-robaho.dockerfile b/frameworks/Java/httpserver/httpserver-robaho.dockerfile index 0943f9f7ef2..d8ab493ec98 100644 --- a/frameworks/Java/httpserver/httpserver-robaho.dockerfile +++ b/frameworks/Java/httpserver/httpserver-robaho.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies EXPOSE 8080 -CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-Drobaho.net.httpserver.nodelay=true", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver.dockerfile b/frameworks/Java/httpserver/httpserver.dockerfile index 2de799e386d..9be7804fed6 100644 --- a/frameworks/Java/httpserver/httpserver.dockerfile +++ b/frameworks/Java/httpserver/httpserver.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3-eclipse-temurin-24-alpine as maven +FROM maven:3-eclipse-temurin-25-alpine as maven WORKDIR /httpserver COPY pom.xml pom.xml COPY src src @@ -10,4 +10,4 @@ COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar ap EXPOSE 8080 -CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:MaxRAMPercentage=70", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dsun.net.httpserver.nodelay=true", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/pom.xml b/frameworks/Java/httpserver/pom.xml index 58cf78deeda..239de4734e0 100644 --- a/frameworks/Java/httpserver/pom.xml +++ b/frameworks/Java/httpserver/pom.xml @@ -71,8 +71,8 @@ 3.14.1 false - 21 - 21 + 25 + 25 diff --git a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java index 799f183f46b..27ca4729638 100755 --- a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java +++ b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java @@ -54,11 +54,11 @@ private static List queryFortunes(DataSource ds) throws SQLException { private static DataSource createPostgresDataSource() { HikariConfig config = new HikariConfig(); - config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); + config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world?tlsnowait=true"); config.setUsername("benchmarkdbuser"); config.setPassword("benchmarkdbpass"); - config.setMaximumPoolSize(64); + config.setMaximumPoolSize(1024); config.setMinimumIdle(0); config.setConnectionTimeout(1000); @@ -88,6 +88,7 @@ private static HttpHandler createPlaintextHandler() { t.getResponseHeaders().add("Server", SERVER_NAME); t.sendResponseHeaders(200, HELLO_LENGTH); t.getResponseBody().write(HELLO_BYTES); + t.getResponseBody().flush(); t.getResponseBody().close(); }; } @@ -131,6 +132,7 @@ private static HttpHandler createFortunesHandler(DataSource ds) throws IOExcepti t.getResponseHeaders().add("Server", SERVER_NAME); t.sendResponseHeaders(200, bytes.length); t.getResponseBody().write(bytes); + t.getResponseBody().flush(); t.getResponseBody().close(); } catch (SQLException | ParseException e) { throw new IOException(e); @@ -146,13 +148,11 @@ static void main(String[] args) throws Exception { System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "DEBUG"); // create server HttpServer server = HttpServer.create(new InetSocketAddress(port), 1024 * 8); - server.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); + server.setExecutor(Executors.newCachedThreadPool()); server.createContext("/plaintext", createPlaintextHandler()); server.createContext("/json", createJSONHandler()); - if (settings.contains("postgres")) { - DataSource ds = createPostgresDataSource(); - server.createContext("/fortunes", createFortunesHandler(ds)); - } + DataSource ds = createPostgresDataSource(); + server.createContext("/fortunes", createFortunesHandler(ds)); // start server server.start(); } diff --git a/frameworks/Java/isocket-nio/benchmark_config.json b/frameworks/Java/isocket-nio/benchmark_config.json index 4e56cc1fd40..eb0d3986cb2 100644 --- a/frameworks/Java/isocket-nio/benchmark_config.json +++ b/frameworks/Java/isocket-nio/benchmark_config.json @@ -19,7 +19,8 @@ "database_os": "Linux", "display_name": "isocket-nio", "notes": "", - "versus": "isocket-nio" + "versus": "isocket-nio", + "tags": [ "broken" ] } } ] diff --git a/frameworks/Java/light-java/pom.xml b/frameworks/Java/light-java/pom.xml index c4f19482f33..e38b1c89c77 100644 --- a/frameworks/Java/light-java/pom.xml +++ b/frameworks/Java/light-java/pom.xml @@ -25,7 +25,7 @@ 11 2.0.1 1.3.12 - 2.3.20.Final + 2.3.21.Final 3.3.1 8.0.28 42.7.2 diff --git a/frameworks/Java/loveqq/README.md b/frameworks/Java/loveqq/README.md new file mode 100644 index 00000000000..4eddc224f6d --- /dev/null +++ b/frameworks/Java/loveqq/README.md @@ -0,0 +1,60 @@ +# Loveqq MVC Benchmarking Test + +This is the Loveqq MVC portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +An embedded reactor-netty is used for the web server. + +### Plaintext Test + +* [Plaintext test source](src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java) + +### JSON Serialization Test + +* [JSON test source](src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java) + +### Database Query Test + +* [Database Query test source](src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java) + +### Database Queries Test + +* [Database Queries test source](src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java) + +### Database Update Test + +* [Database Update test source](src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java) + +### Template rendering Test + +* [Template rendering test source](src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java) + +## Versions + +* [Java OpenJDK 21](http://openjdk.java.net/) +* [loveqq-framework 1.1.6-M5](http://github.com/kfyty/loveqq-framework) + +## Test URLs + +### Plaintext Test + + http://localhost:8080/plaintext + +### JSON Encoding Test + + http://localhost:8080/json + +### Database Query Test + + http://localhost:8080/db + +### Database Queries Test + + http://localhost:8080/queries?queries=5 + +### Database Update Test + + http://localhost:8080/updates?queries=5 + +### Template rendering Test + + http://localhost:8080/fortunes diff --git a/frameworks/Java/loveqq/benchmark_config.json b/frameworks/Java/loveqq/benchmark_config.json new file mode 100644 index 00000000000..def02465949 --- /dev/null +++ b/frameworks/Java/loveqq/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "loveqq", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "loveqq", + "language": "Java", + "flavor": "None", + "orm": "Micro", + "platform": "Netty", + "webserver": "reactor-netty", + "os": "Linux", + "database_os": "Linux", + "display_name": "loveqq", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Java/loveqq/config.toml b/frameworks/Java/loveqq/config.toml new file mode 100644 index 00000000000..5b7312c2ab8 --- /dev/null +++ b/frameworks/Java/loveqq/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "loveqq" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "Netty" +webserver = "reactor-netty" +versus = "" diff --git a/frameworks/Java/loveqq/loveqq.dockerfile b/frameworks/Java/loveqq/loveqq.dockerfile new file mode 100644 index 00000000000..2a204a648ba --- /dev/null +++ b/frameworks/Java/loveqq/loveqq.dockerfile @@ -0,0 +1,14 @@ +FROM maven:3.9.7-amazoncorretto-21 as maven +WORKDIR /loveqq +COPY src src +COPY pom.xml pom.xml +RUN mvn package -P !default,!dev,!gpg + +FROM bellsoft/liberica-openjre-debian:22 +WORKDIR /loveqq +COPY --from=maven /loveqq/target/boot-lib boot-lib +COPY --from=maven /loveqq/target/loveqq-benchmark-1.0-SNAPSHOT.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED", "--add-opens=java.base/sun.reflect.annotation=ALL-UNNAMED", "-jar", "app.jar"] \ No newline at end of file diff --git a/frameworks/Java/loveqq/pom.xml b/frameworks/Java/loveqq/pom.xml new file mode 100644 index 00000000000..79a49cbe303 --- /dev/null +++ b/frameworks/Java/loveqq/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + + com.kfyty + loveqq-framework + 1.1.6-M5 + + + loveqq-benchmark + 1.0-SNAPSHOT + + + 21 + 42.7.7 + 1.3.6 + com.kfyty.benchmark.example.Main + + + + + com.kfyty + loveqq-boot + ${loveqq.framework.version} + + + + com.kfyty + loveqq-boot-starter-datasource + ${loveqq.framework.version} + + + + com.kfyty + loveqq-boot-starter-netty + ${loveqq.framework.version} + + + + com.kfyty + loveqq-boot-starter-logback + ${loveqq.framework.version} + + + + org.yaml + snakeyaml + + + + org.postgresql + postgresql + ${postgresql.version} + + + + io.jstach + jstachio + ${jstachio.version} + + + + io.jstach + jstachio-apt + ${jstachio.version} + provided + + + + com.kfyty + loveqq-boot-starter-test + ${loveqq.framework.version} + test + + + \ No newline at end of file diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/Main.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/Main.java new file mode 100644 index 00000000000..da61682df29 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/Main.java @@ -0,0 +1,14 @@ +package com.kfyty.benchmark.example; + +import com.kfyty.loveqq.framework.boot.K; +import com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication; +import com.kfyty.loveqq.framework.web.core.autoconfig.annotation.EnableWebMvc; + +@EnableWebMvc +@BootApplication +public class Main { + + public static void main(String[] args) { + K.start(Main.class, args); + } +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java new file mode 100644 index 00000000000..d2d9bef5b59 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/controller/WebMvcController.java @@ -0,0 +1,111 @@ +package com.kfyty.benchmark.example.controller; + +import com.kfyty.benchmark.example.model.Fortune; +import com.kfyty.benchmark.example.model.Fortunes; +import com.kfyty.benchmark.example.model.World; +import com.kfyty.benchmark.example.repository.DbRepository; +import com.kfyty.benchmark.example.utils.Utils; +import com.kfyty.loveqq.framework.web.core.annotation.GetMapping; +import com.kfyty.loveqq.framework.web.core.annotation.RestController; +import com.kfyty.loveqq.framework.web.core.annotation.bind.RequestParam; +import com.kfyty.loveqq.framework.web.core.http.ServerResponse; +import io.jstach.jstachio.JStachio; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +@RestController +public class WebMvcController { + private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8); + + private final DbRepository dbRepository; + + public WebMvcController(DbRepository dbRepository) { + this.dbRepository = dbRepository; + } + + /** + * GET /plaintext HTTP/1.1 + */ + @GetMapping(value = "/plaintext", produces = "text/plain; charset=UTF-8") + public byte[] plaintext(ServerResponse response) { + response.setHeader("Content-Length", "13"); + return TEXT_BODY; + } + + /** + * GET /json HTTP/1.1 + */ + @GetMapping(value = "/json") + public Map json(ServerResponse response) { + response.setHeader("Content-Length", "27"); + return Map.of("message", "Hello, world!"); + } + + /** + * GET /db HTTP/1.1 + */ + @GetMapping("/db") + public World db() { + return dbRepository.getWorld(Utils.randomWorldNumber()); + } + + /** + * GET /queries?queries=10 HTTP/1.1 + */ + @GetMapping("/queries") + public World[] queries(@RequestParam(defaultValue = "1") String queries) { + return Utils.randomWorldNumbers().limit(parseQueryCount(queries)).mapToObj(dbRepository::getWorld).toArray(World[]::new); + } + + /** + * GET /updates?queries=10 HTTP/1.1 + */ + @GetMapping("/updates") + public List updates(@RequestParam(defaultValue = "1") String queries) { + List worlds = Utils.randomWorldNumbers() + .limit(parseQueryCount(queries)) + .mapToObj(id -> { + World world = dbRepository.getWorld(id); + int randomNumber; + do { + randomNumber = Utils.randomWorldNumber(); + } while (randomNumber == world.randomNumber); + world.randomNumber = randomNumber; + return world; + }) + .sorted(Comparator.comparingInt(w -> w.id)) + .toList(); + dbRepository.updateWorlds(worlds); + return worlds; + } + + /** + * GET /fortunes HTTP/1.1 + */ + @GetMapping(value = "/fortunes", produces = "text/html; charset=UTF-8") + public String fortunes() { + List fortunes = dbRepository.fortunes(); + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + + Collections.sort(fortunes); + + return JStachio.render(new Fortunes(fortunes)); + } + + private static int parseQueryCount(String textValue) { + if (textValue == null) { + return 1; + } + int parsedValue; + try { + parsedValue = Integer.parseInt(textValue); + } catch (NumberFormatException e) { + return 1; + } + return Math.min(500, Math.max(1, parsedValue)); + } +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/filter/ResponseHeaderFilter.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/filter/ResponseHeaderFilter.java new file mode 100644 index 00000000000..e14f0ad0ab5 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/filter/ResponseHeaderFilter.java @@ -0,0 +1,25 @@ +package com.kfyty.benchmark.example.filter; + +import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component; +import com.kfyty.loveqq.framework.web.core.filter.Filter; +import com.kfyty.loveqq.framework.web.core.filter.FilterChain; +import com.kfyty.loveqq.framework.web.core.http.ServerRequest; +import com.kfyty.loveqq.framework.web.core.http.ServerResponse; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Component +public class ResponseHeaderFilter implements Filter { + private static final Clock clock = Clock.systemDefaultZone(); + + @Override + public Publisher doFilter(ServerRequest request, ServerResponse response, FilterChain chain) { + response.setHeader("Server", "loveqq"); + response.setHeader("Date", DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(clock))); + return Mono.from(chain.doFilter(request, response)); + } +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/Fortune.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/Fortune.java new file mode 100644 index 00000000000..60254d706ba --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/Fortune.java @@ -0,0 +1,19 @@ +package com.kfyty.benchmark.example.model; + +public final class Fortune implements Comparable{ + public int id; + public String message; + + public Fortune() { + } + + public Fortune(int id, String message) { + this.id = id; + this.message = message; + } + + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); + } +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/Fortunes.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/Fortunes.java new file mode 100644 index 00000000000..839d8512916 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/Fortunes.java @@ -0,0 +1,9 @@ +package com.kfyty.benchmark.example.model; + +import io.jstach.jstache.JStache; + +import java.util.List; + +@JStache(path = "fortunes.mustache") +public record Fortunes(List fortunes) { +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/World.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/World.java new file mode 100644 index 00000000000..fe0645eb720 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/model/World.java @@ -0,0 +1,14 @@ +package com.kfyty.benchmark.example.model; + +public final class World { + public int id; + public int randomNumber; + + public World() { + } + + public World(int id, int randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } +} \ No newline at end of file diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/repository/DbRepository.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/repository/DbRepository.java new file mode 100644 index 00000000000..5f7de0d2384 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/repository/DbRepository.java @@ -0,0 +1,15 @@ +package com.kfyty.benchmark.example.repository; + +import com.kfyty.benchmark.example.model.Fortune; +import com.kfyty.benchmark.example.model.World; + +import java.util.List; + +public interface DbRepository { + + World getWorld(int id); + + void updateWorlds(List worlds); + + List fortunes(); +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/repository/JdbcDbRepository.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/repository/JdbcDbRepository.java new file mode 100644 index 00000000000..794ee502fc6 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/repository/JdbcDbRepository.java @@ -0,0 +1,55 @@ +package com.kfyty.benchmark.example.repository; + +import com.kfyty.benchmark.example.model.Fortune; +import com.kfyty.benchmark.example.model.World; +import com.kfyty.loveqq.framework.core.autoconfig.annotation.Repository; +import com.kfyty.loveqq.framework.core.exception.ResolvableException; +import com.kfyty.loveqq.framework.core.generic.SimpleGeneric; +import com.kfyty.loveqq.framework.core.reflect.DefaultParameterizedType; +import com.kfyty.loveqq.framework.core.utils.JdbcUtil; + +import javax.sql.DataSource; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; + +@Repository +public class JdbcDbRepository implements DbRepository { + private final DataSource dataSource; + + public JdbcDbRepository(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public World getWorld(int id) { + try { + return JdbcUtil.query(dataSource, World.class, "SELECT id, randomnumber FROM world WHERE id = ?", id); + } catch (SQLException e) { + return null; + } + } + + @Override + public void updateWorlds(List worlds) { + try { + for (World world : worlds) { + JdbcUtil.execute(dataSource, "UPDATE world SET randomnumber = ? WHERE id = ?", world.randomNumber, world.id); + } + } catch (SQLException e) { + throw new ResolvableException(e); + } + } + + @Override + @SuppressWarnings("unchecked") + public List fortunes() { + try { + DefaultParameterizedType parameterizedType = new DefaultParameterizedType(List.class, new Class[]{Fortune.class}); + Object queried = JdbcUtil.query(dataSource, SimpleGeneric.from(parameterizedType), "SELECT id, message FROM fortune"); + return (List) queried; + } catch (SQLException e) { + return new LinkedList<>(); + } + } +} diff --git a/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/utils/Utils.java b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/utils/Utils.java new file mode 100644 index 00000000000..2f6f2ac3b87 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/java/com/kfyty/benchmark/example/utils/Utils.java @@ -0,0 +1,17 @@ +package com.kfyty.benchmark.example.utils; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +public abstract class Utils { + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; + + public static int randomWorldNumber() { + return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); + } + + public static IntStream randomWorldNumbers() { + return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE).distinct(); + } +} diff --git a/frameworks/Java/loveqq/src/main/resources/application.yml b/frameworks/Java/loveqq/src/main/resources/application.yml new file mode 100644 index 00000000000..1e414cdf380 --- /dev/null +++ b/frameworks/Java/loveqq/src/main/resources/application.yml @@ -0,0 +1,12 @@ +k: + server: + virtualThread: false + datasource: + type: com.zaxxer.hikari.HikariDataSource + driverClassName: org.postgresql.Driver + username: benchmarkdbuser + password: benchmarkdbpass + url: jdbc:postgresql://tfb-database:5432/hello_world?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable + hikari: + minIdle: 5 + maxPoolSize: 256 diff --git a/frameworks/Java/loveqq/src/main/resources/fortunes.mustache b/frameworks/Java/loveqq/src/main/resources/fortunes.mustache new file mode 100644 index 00000000000..3043546205b --- /dev/null +++ b/frameworks/Java/loveqq/src/main/resources/fortunes.mustache @@ -0,0 +1,20 @@ + + + + Fortunes + + +
idmessage
+ + + + + {{#fortunes}} + + + + + {{/fortunes}} +
idmessage
{{id}}{{message}}
+ + diff --git a/frameworks/Java/magician-io/benchmark_config.json b/frameworks/Java/magician-io/benchmark_config.json index 8a7db88fe96..d92773bf31a 100644 --- a/frameworks/Java/magician-io/benchmark_config.json +++ b/frameworks/Java/magician-io/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "magician-io", "notes": "magician io", - "versus": "magician" + "versus": "" } }] } \ No newline at end of file diff --git a/frameworks/Java/martian/README.md b/frameworks/Java/martian/README.md deleted file mode 100644 index 9a2d5ee24b6..00000000000 --- a/frameworks/Java/martian/README.md +++ /dev/null @@ -1,12 +0,0 @@ -## Martian Benchmarking Test - -This is Martian's official website address[http://mars-framework.com/](http://mars-framework.com/) - -## Versions - -- Java OpenJDK 1.8 -- Martian 3.2.13 - -##Test URLs -### JSON Encoding Test -http://localhost:8080/json \ No newline at end of file diff --git a/frameworks/Java/martian/benchmark_config.json b/frameworks/Java/martian/benchmark_config.json deleted file mode 100644 index 684e4e1df6a..00000000000 --- a/frameworks/Java/martian/benchmark_config.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "framework": "martian", - "tests": [{ - "default": { - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "martian", - "language": "Java", - "flavor": "None", - "orm": "None", - "platform": "Martian", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "martian-mvc", - "notes": "martian webserver with mvc", - "versus": "martian" - } - }] -} \ No newline at end of file diff --git a/frameworks/Java/martian/martian.dockerfile b/frameworks/Java/martian/martian.dockerfile deleted file mode 100644 index 014401ed748..00000000000 --- a/frameworks/Java/martian/martian.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM maven:3.6.1-jdk-11-slim as maven -WORKDIR /martian -COPY pom.xml pom.xml -COPY src src -RUN mvn package -q - -FROM openjdk:11.0.3-jdk-slim -WORKDIR /martian -COPY --from=maven /martian/target/martian.jar martian.jar -COPY --from=maven /martian/target/lib lib - -EXPOSE 8080 - -CMD ["java", "-jar", "martian.jar"] \ No newline at end of file diff --git a/frameworks/Java/martian/pom.xml b/frameworks/Java/martian/pom.xml deleted file mode 100644 index 19bb461c0f8..00000000000 --- a/frameworks/Java/martian/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - 4.0.0 - - org.example - martian - 1.0-SNAPSHOT - - UTF-8 - 11 - 11 - - - - - - com.github.yuyenews - Martian - 4.0.3 - - - com.github.yuyenews - Magician - - - - - - com.github.yuyenews - Magician - 1.1.15 - - - - - - org.slf4j - slf4j-jdk14 - 1.7.12 - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - martian - - - com.text.Start - true - ./lib/ - false - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy - package - - copy-dependencies - - - ${project.build.directory}/lib - - - - - - - \ No newline at end of file diff --git a/frameworks/Java/martian/src/main/java/com/text/Start.java b/frameworks/Java/martian/src/main/java/com/text/Start.java deleted file mode 100644 index d32751d7a0a..00000000000 --- a/frameworks/Java/martian/src/main/java/com/text/Start.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.text; - -import com.martian.annotation.MartianScan; -import com.martian.starter.StartMartian; -import com.text.config.TestConfig; - -@MartianScan(scanPackage = "com.text.api") -public class Start { - - public static void main(String[] args) { - StartMartian.start(Start.class, new TestConfig()); - } -} diff --git a/frameworks/Java/martian/src/main/java/com/text/api/TestApi.java b/frameworks/Java/martian/src/main/java/com/text/api/TestApi.java deleted file mode 100644 index 4e1ec2a28c9..00000000000 --- a/frameworks/Java/martian/src/main/java/com/text/api/TestApi.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.text.api; - -import com.magician.web.core.annotation.Route; -import com.text.api.vo.MessageVO; -import io.magician.tcp.codec.impl.http.request.MagicianRequest; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -public class TestApi { - - private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("E, dd MMM yyyy H:m:s z", Locale.US); - - @Route("/json") - public MessageVO json(MagicianRequest request){ - - String str = simpleDateFormat.format(new Date()); - - request.getResponse() - .setResponseHeader("Server","Martian") - .setResponseHeader("Date", str); - - MessageVO messageVO = new MessageVO(); - messageVO.setMessage("Hello, World!"); - return messageVO; - } -} diff --git a/frameworks/Java/martian/src/main/java/com/text/api/vo/MessageVO.java b/frameworks/Java/martian/src/main/java/com/text/api/vo/MessageVO.java deleted file mode 100644 index 61965b63768..00000000000 --- a/frameworks/Java/martian/src/main/java/com/text/api/vo/MessageVO.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.text.api.vo; - -public class MessageVO { - - private String message; - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/frameworks/Java/martian/src/main/java/com/text/config/TestConfig.java b/frameworks/Java/martian/src/main/java/com/text/config/TestConfig.java deleted file mode 100644 index 789496a6189..00000000000 --- a/frameworks/Java/martian/src/main/java/com/text/config/TestConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.text.config; - -import com.martian.config.MartianConfig; -import io.magician.common.event.EventGroup; - -import java.util.concurrent.Executors; - -public class TestConfig extends MartianConfig { - - @Override - public int port() { - return 8080; - } - - @Override - public EventGroup workerEventGroup() { - return new EventGroup(10, Executors.newCachedThreadPool()); - } -} diff --git a/frameworks/Java/microhttp/pom.xml b/frameworks/Java/microhttp/pom.xml index 75ad3849dfb..79b894c2c87 100644 --- a/frameworks/Java/microhttp/pom.xml +++ b/frameworks/Java/microhttp/pom.xml @@ -24,7 +24,7 @@ com.fasterxml.jackson.core jackson-core - 2.15.0 + 2.18.6 com.fasterxml.jackson.core diff --git a/frameworks/Java/micronaut/README.md b/frameworks/Java/micronaut/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Java/micronaut/benchmark_config.json b/frameworks/Java/micronaut/benchmark_config.json old mode 100755 new mode 100644 index db44857f540..721e37a021d --- a/frameworks/Java/micronaut/benchmark_config.json +++ b/frameworks/Java/micronaut/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "micronaut", + "maintainers": ["dstepanov", "yawkat", "graemerocher"], "tests": [ { "default": { @@ -23,7 +24,8 @@ "database_os": "Linux", "display_name": "Micronaut [Vertx PG Client]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "graalvm": { "json_url": "/json", @@ -46,7 +48,8 @@ "database_os": "Linux", "display_name": "Micronaut [Vertx PG Client] [GraalVM]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "loom-fjp": { "json_url": "/json", @@ -69,7 +72,8 @@ "database_os": "Linux", "display_name": "Micronaut [Vertx PG Client] [Virtual Threads FJP]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "loom-on-netty": { "json_url": "/json", @@ -92,7 +96,8 @@ "database_os": "Linux", "display_name": "Micronaut [Vertx PG Client] [Virtual Threads Loom-On-Netty]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "jdbc": { "db_url": "/db", @@ -113,7 +118,8 @@ "database_os": "Linux", "display_name": "Micronaut [JDBC]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "jdbc-graalvm": { "db_url": "/db", @@ -134,7 +140,8 @@ "database_os": "Linux", "display_name": "Micronaut [JDBC] [GraalVM]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "r2dbc": { "db_url": "/db", @@ -155,7 +162,8 @@ "database_os": "Linux", "display_name": "Micronaut [R2DBC]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "r2dbc-graalvm": { "db_url": "/db", @@ -176,7 +184,8 @@ "database_os": "Linux", "display_name": "Micronaut [R2DBC] [GraalVM]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "data-jdbc": { "db_url": "/db", @@ -197,7 +206,8 @@ "database_os": "Linux", "display_name": "Micronaut [Data JDBC]", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] }, "data-jdbc-graalvm": { "db_url": "/db", @@ -218,49 +228,8 @@ "database_os": "Linux", "display_name": "Micronaut [Data JDBC] [GraalVM]", "notes": "", - "versus": "None" - }, - "data-mongodb": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "fullstack", - "database": "MongoDB", - "framework": "Micronaut", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "Netty", - "os": "Linux", - "database_os": "Linux", - "display_name": "Micronaut [Data MongoDB]", - "notes": "", - "versus": "None" - }, - "data-mongodb-graalvm": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "fullstack", - "database": "MongoDB", - "framework": "Micronaut", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "Netty", - "os": "Linux", - "database_os": "Linux", - "display_name": "Micronaut [Data MongoDB] [GraalVM]", - "notes": "", - "versus": "None" + "versus": "None", + "tags": [] } } ] diff --git a/frameworks/Java/micronaut/buildSrc/build.gradle b/frameworks/Java/micronaut/buildSrc/build.gradle index c0dfaa40cbc..66a82495139 100644 --- a/frameworks/Java/micronaut/buildSrc/build.gradle +++ b/frameworks/Java/micronaut/buildSrc/build.gradle @@ -8,6 +8,6 @@ repositories { } dependencies { - implementation "io.micronaut.gradle:micronaut-gradle-plugin:4.5.4" - implementation "com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:8.1.1" + implementation "io.micronaut.gradle:micronaut-gradle-plugin:4.6.2" + implementation "com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.3.1" } \ No newline at end of file diff --git a/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle b/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle index dcb6b3389fc..6572ea7e1a5 100644 --- a/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle +++ b/frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle @@ -2,7 +2,7 @@ plugins { id 'java' id "io.micronaut.application" id 'io.micronaut.test-resources' - id 'com.github.johnrengelman.shadow' + id 'com.gradleup.shadow' } repositories { @@ -29,6 +29,7 @@ dependencies { graalvmNative.binaries.all { buildArgs.add("--initialize-at-build-time=gg.jte.generated.precompiled") + buildArgs.add("-H:+SharedArenaSupport") } test { diff --git a/frameworks/Java/micronaut/gradle.properties b/frameworks/Java/micronaut/gradle.properties index 691f3e86c3c..47457fd8687 100644 --- a/frameworks/Java/micronaut/gradle.properties +++ b/frameworks/Java/micronaut/gradle.properties @@ -1 +1 @@ -micronautVersion=4.9.2 +micronautVersion=4.10.7 diff --git a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties index d4081da476b..37f78a6af83 100644 --- a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile index 5cd7c898d38..3a2b729457a 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:24 +FROM container-registry.oracle.com/graalvm/native-image:25 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile b/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile index 3f41572b0d1..2b1035dbe7c 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-data-jdbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/libs/micronaut-data-jdbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile index 2523f8a8c9d..40dbe8c391c 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:24 +FROM container-registry.oracle.com/graalvm/native-image:25 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile b/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile index f0265880881..262b0ff62e9 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-data-mongodb:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/libs/micronaut-data-mongodb-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile index d96f5945b06..c34d9501bd9 100644 --- a/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:24 +FROM container-registry.oracle.com/graalvm/native-image:25 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile b/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile index 3caef969781..cc4ad443c41 100644 --- a/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-data-r2dbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/libs/micronaut-data-r2dbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile index 5638f4242bb..e54951ddc33 100644 --- a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:24 +FROM container-registry.oracle.com/graalvm/native-image:25 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile index 5defe25a9ad..ee45cacb8bc 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:24 +FROM container-registry.oracle.com/graalvm/native-image:25 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-jdbc.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc.dockerfile index 08af177c9e2..1bc0bf818bf 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-jdbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-jdbc/build/libs/micronaut-jdbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile b/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile index 29ceea4e896..b8bce5bad7b 100644 --- a/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile +++ b/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-vertx-pg-client:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/libs/micronaut-vertx-pg-client-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile b/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile index 76f2cdebfa6..789d4584767 100644 --- a/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile +++ b/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-vertx-pg-client:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/libs/micronaut-vertx-pg-client-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile index 32c282bbcd2..6747f77ff83 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM container-registry.oracle.com/graalvm/native-image:24 +FROM container-registry.oracle.com/graalvm/native-image:25 RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src diff --git a/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile index 1ddbd04a84c..174db2d4551 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-r2dbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-r2dbc/build/libs/micronaut-r2dbc-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/micronaut/micronaut-vertx-pg-client/build.gradle b/frameworks/Java/micronaut/micronaut-vertx-pg-client/build.gradle index fe8dd5d09bf..eb2b8cc4ef6 100644 --- a/frameworks/Java/micronaut/micronaut-vertx-pg-client/build.gradle +++ b/frameworks/Java/micronaut/micronaut-vertx-pg-client/build.gradle @@ -9,6 +9,6 @@ micronaut { } dependencies { - implementation("io.vertx:vertx-pg-client:5.0.2") - implementation('com.ongres.scram:client') -} \ No newline at end of file + implementation("io.vertx:vertx-pg-client:5.0.7") + implementation('com.ongres.scram:scram-client:3.2') +} diff --git a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java index 6d7d91cd3f9..114b6739ac0 100644 --- a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java +++ b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java @@ -28,7 +28,6 @@ import io.vertx.core.spi.transport.Transport; import io.vertx.pgclient.PgConnectOptions; import io.vertx.pgclient.PgConnection; -import io.vertx.sqlclient.PoolOptions; import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -125,12 +124,6 @@ private static io.vertx.core.transport.Transport vertxTransport() { .findFirst().orElseThrow(); } - private PoolOptions poolOptions() { - PoolOptions poolOptions = new PoolOptions(); - poolOptions.setMaxSize(maxPoolSize); - return poolOptions; - } - private PgConnectOptions connectOptions() { return PgConnectOptions.fromUri(url.substring(5)) .setUser(user) diff --git a/frameworks/Java/micronaut/micronaut.dockerfile b/frameworks/Java/micronaut/micronaut.dockerfile index b50cc0fa117..2bfa7f05e50 100644 --- a/frameworks/Java/micronaut/micronaut.dockerfile +++ b/frameworks/Java/micronaut/micronaut.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.14.3-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle micronaut-vertx-pg-client:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:24 +FROM container-registry.oracle.com/java/openjdk:25.0.2 WORKDIR /micronaut COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/libs/micronaut-vertx-pg-client-all.jar micronaut.jar COPY run_benchmark.sh run_benchmark.sh diff --git a/frameworks/Java/netty/benchmark_config.json b/frameworks/Java/netty/benchmark_config.json index 79c322fef4e..47568225801 100644 --- a/frameworks/Java/netty/benchmark_config.json +++ b/frameworks/Java/netty/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "netty", "notes": "", - "versus": "netty" + "versus": "" }, "loom": { "json_url": "/json", diff --git a/frameworks/Java/netty/config.toml b/frameworks/Java/netty/config.toml index bea6d72db37..3db4fb11471 100644 --- a/frameworks/Java/netty/config.toml +++ b/frameworks/Java/netty/config.toml @@ -12,7 +12,7 @@ os = "Linux" orm = "Raw" platform = "Netty" webserver = "None" -versus = "netty" +versus = "" [loom] urls.plaintext = "/plaintext" diff --git a/frameworks/Java/officefloor/benchmark_config.json b/frameworks/Java/officefloor/benchmark_config.json index d90efc51b9d..7bd46a45e1e 100755 --- a/frameworks/Java/officefloor/benchmark_config.json +++ b/frameworks/Java/officefloor/benchmark_config.json @@ -23,6 +23,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor", + "tags": ["broken"], "notes": "", "versus": "officefloor-micro" }, @@ -116,6 +117,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-async", + "tags": ["broken"], "notes": "", "versus": "OfficeFloor-r2dbc" }, @@ -140,6 +142,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-micro", + "tags": ["broken"], "notes": "", "versus": "OfficeFloor-r2dbc" }, @@ -164,8 +167,8 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-thread_affinity", - "notes": "", "tags": ["broken"], + "notes": "", "versus": "OfficeFloor-r2dbc" }, "netty": { @@ -189,6 +192,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-netty", + "tags": ["broken"], "notes": "", "versus": "Netty" }, @@ -213,6 +217,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-undertow", + "tags": ["broken"], "notes": "", "versus": "undertow-postgresql" }, @@ -237,6 +242,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-vertx", + "tags": ["broken"], "notes": "", "versus": "vertx-postgres" }, @@ -261,6 +267,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-spring_data", + "tags": ["broken"], "notes": "", "versus": "spring" } diff --git a/frameworks/Java/pippo/benchmark_config.json b/frameworks/Java/pippo/benchmark_config.json index 0ba473feb85..fc7157df851 100755 --- a/frameworks/Java/pippo/benchmark_config.json +++ b/frameworks/Java/pippo/benchmark_config.json @@ -5,23 +5,6 @@ "default": { "json_url": "/json", "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "pippo", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Jetty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "pippo-jetty", - "notes": "", - "versus": "None" - }, - "postgres": { "db_url": "/postgres/db", "query_url": "/postgres/queries?queries=", "update_url": "/postgres/updates?queries=", @@ -38,7 +21,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "pippo-jetty-postgres", + "display_name": "pippo-jetty", "notes": "", "versus": "None" }, @@ -87,23 +70,6 @@ "tomcat": { "json_url": "/json", "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "pippo", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Tomcat", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "pippo-tomcat", - "notes": "", - "versus": "None" - }, - "tomcat-postgres": { "db_url": "/postgres/db", "query_url": "/postgres/queries?queries=", "update_url": "/postgres/updates?queries=", @@ -120,7 +86,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "pippo-tomcat-postgres", + "display_name": "pippo-tomcat", "notes": "", "versus": "None" }, @@ -169,23 +135,6 @@ "undertow": { "json_url": "/json", "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "pippo", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Undertow", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "pippo-undertow", - "notes": "", - "versus": "None" - }, - "undertow-postgres": { "db_url": "/postgres/db", "query_url": "/postgres/queries?queries=", "update_url": "/postgres/updates?queries=", @@ -202,7 +151,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "pippo-undertow-postgres", + "display_name": "pippo-undertow", "notes": "", "versus": "None" }, diff --git a/frameworks/Java/pippo/pippo-postgres.dockerfile b/frameworks/Java/pippo/pippo-postgres.dockerfile deleted file mode 100644 index 5c961c96d14..00000000000 --- a/frameworks/Java/pippo/pippo-postgres.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM gradle:7.6.0-jdk17 as gradle -WORKDIR /pippo -COPY gradle gradle -COPY build.gradle build.gradle -COPY gradlew gradlew -COPY src src -RUN ./gradlew fatJar -x test - -FROM eclipse-temurin:17.0.6_10-jre-jammy -WORKDIR /pippo -COPY --from=gradle /pippo/build/libs/pippo-all.jar app.jar - -ARG BENCHMARK_ENV - -ENV BENCHMARK_ENV=$BENCHMARK_ENV - -EXPOSE 8080 - -CMD ["java", "-server", "-Xms4G", "-Xmx4G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "com.techempower.benchmark.pippo.benchmark.BenchmarkJetty"] diff --git a/frameworks/Java/pippo/pippo-tomcat-postgres.dockerfile b/frameworks/Java/pippo/pippo-tomcat-postgres.dockerfile deleted file mode 100644 index a974523ca5a..00000000000 --- a/frameworks/Java/pippo/pippo-tomcat-postgres.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM gradle:7.6.0-jdk17 as gradle -WORKDIR /pippo -COPY gradle gradle -COPY build.gradle build.gradle -COPY gradlew gradlew -COPY src src -RUN ./gradlew fatJar -x test - -FROM eclipse-temurin:17.0.6_10-jre-jammy -WORKDIR /pippo -COPY --from=gradle /pippo/build/libs/pippo-all.jar app.jar - -ARG BENCHMARK_ENV - -ENV BENCHMARK_ENV=$BENCHMARK_ENV - -EXPOSE 8080 - -CMD ["java", "-server", "-Xms4G", "-Xmx4G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "com.techempower.benchmark.pippo.benchmark.BenchmarkTomcat"] diff --git a/frameworks/Java/pippo/pippo-undertow-postgres.dockerfile b/frameworks/Java/pippo/pippo-undertow-postgres.dockerfile deleted file mode 100644 index 7cc2de55b64..00000000000 --- a/frameworks/Java/pippo/pippo-undertow-postgres.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM gradle:7.6.0-jdk17 as gradle -WORKDIR /pippo -COPY gradle gradle -COPY build.gradle build.gradle -COPY gradlew gradlew -COPY src src -RUN ./gradlew fatJar -x test - -FROM eclipse-temurin:17.0.6_10-jre-jammy -WORKDIR /pippo -COPY --from=gradle /pippo/build/libs/pippo-all.jar app.jar - -ARG BENCHMARK_ENV - -ENV BENCHMARK_ENV=$BENCHMARK_ENV - -EXPOSE 8080 - -CMD ["java", "-server", "-Xms4G", "-Xmx4G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "com.techempower.benchmark.pippo.benchmark.BenchmarkUndertow"] diff --git a/frameworks/Java/proteus/benchmark_config.json b/frameworks/Java/proteus/benchmark_config.json index 73829ffc566..3627c5e8e39 100644 --- a/frameworks/Java/proteus/benchmark_config.json +++ b/frameworks/Java/proteus/benchmark_config.json @@ -20,7 +20,8 @@ "database_os": "Linux", "display_name": "proteus", "notes": "", - "versus": "" + "versus": "", + "tags": ["broken"] }, "mysql" : { "db_url": "/db/mysql", @@ -39,7 +40,8 @@ "database_os": "Linux", "display_name": "proteus-mysql", "notes": "", - "versus": "" + "versus": "", + "tags": ["broken"] } }] } \ No newline at end of file diff --git a/frameworks/Java/quarkus/benchmark_config.json b/frameworks/Java/quarkus/benchmark_config.json index dd7fa017935..2c335e339c3 100644 --- a/frameworks/Java/quarkus/benchmark_config.json +++ b/frameworks/Java/quarkus/benchmark_config.json @@ -70,7 +70,8 @@ "database_os": "Linux", "display_name": "Quarkus, Vert.x", "notes": "", - "versus": "Vert.x" + "versus": "Vert.x", + "tags": [] }, "reactive-routes-pgclient": { "json_url": "/json", diff --git a/frameworks/Java/quarkus/vertx/pom.xml b/frameworks/Java/quarkus/vertx/pom.xml index 1414a21df4a..a5c6cdbcdde 100644 --- a/frameworks/Java/quarkus/vertx/pom.xml +++ b/frameworks/Java/quarkus/vertx/pom.xml @@ -24,6 +24,10 @@ io.vertx vertx-pg-client + + com.ongres.scram + client + io.quarkus quarkus-vertx diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java index 4289a644669..edfa939935d 100644 --- a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java @@ -1,5 +1,6 @@ package io.quarkus.benchmark.repository; +import io.quarkus.logging.Log; import io.vertx.core.Vertx; import io.vertx.pgclient.PgConnectOptions; import jakarta.annotation.PreDestroy; @@ -36,7 +37,7 @@ PgConnectionPool connectionPool() { try { pgConnectionPool = new PgConnectionPool(vertx, pgConnectOptions()); } catch (final Exception e) { - // TODO LOG ME: usually means inability to connect to the database + Log.error("Failed to create pgConnectionPool", e); } finally { this.pgConnectionPool = pgConnectionPool; return pgConnectionPool; diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgConnectionPool.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgConnectionPool.java index 0a04a9fde25..e8bf4b32451 100644 --- a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgConnectionPool.java +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgConnectionPool.java @@ -68,7 +68,7 @@ public PgConnectionPool(final Vertx vertx, final PgConnectOptions options) { final AsyncResult ar = completedConnections.get(i); if (ar == null || ar.failed()) { forceCloseEstablishedConnections(completedConnections); - throw new IllegalStateException("cannot establish all connections"); + throw new IllegalStateException("cannot establish all connections", ar != null ? ar.cause() : null); } else { pgConnections.set(i, ar.result()); } diff --git a/frameworks/Java/redkale/benchmark_config.json b/frameworks/Java/redkale/benchmark_config.json index 52f8550ce9f..001cd474756 100644 --- a/frameworks/Java/redkale/benchmark_config.json +++ b/frameworks/Java/redkale/benchmark_config.json @@ -24,7 +24,7 @@ "database_os": "Linux", "display_name": "redkale", "notes": "", - "versus": "Redkale" + "versus": "" }, "native": { "plaintext_url": "/plaintext", diff --git a/frameworks/Java/redkale/config.toml b/frameworks/Java/redkale/config.toml index 149aaad007e..c2b8416ae71 100644 --- a/frameworks/Java/redkale/config.toml +++ b/frameworks/Java/redkale/config.toml @@ -17,7 +17,7 @@ os = "Linux" orm = "Raw" platform = "Redkale" webserver = "Redkale" -versus = "Redkale" +versus = "" [native] urls.plaintext = "/plaintext" diff --git a/frameworks/Java/redkale/pom-jdbc.xml b/frameworks/Java/redkale/pom-jdbc.xml index 8483c39801d..a40b480d804 100644 --- a/frameworks/Java/redkale/pom-jdbc.xml +++ b/frameworks/Java/redkale/pom-jdbc.xml @@ -7,7 +7,7 @@ org.redkale.boot.Application - 2.8.1-SNAPSHOT + 2.8.2-SNAPSHOT 1.2.0 42.7.2 UTF-8 @@ -44,7 +44,7 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots @@ -57,7 +57,7 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots false diff --git a/frameworks/Java/redkale/pom-pgclient.xml b/frameworks/Java/redkale/pom-pgclient.xml index 10ee48261f9..f75b56ca53a 100644 --- a/frameworks/Java/redkale/pom-pgclient.xml +++ b/frameworks/Java/redkale/pom-pgclient.xml @@ -7,7 +7,7 @@ org.redkale.boot.Application - 2.8.1-SNAPSHOT + 2.8.2-SNAPSHOT 1.2.0 4.5.8 2.1 @@ -51,7 +51,7 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots @@ -64,7 +64,7 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots false diff --git a/frameworks/Java/redkale/pom.xml b/frameworks/Java/redkale/pom.xml index c8ef3afb031..0faa81c2537 100644 --- a/frameworks/Java/redkale/pom.xml +++ b/frameworks/Java/redkale/pom.xml @@ -7,7 +7,7 @@ org.redkale.boot.Application - 2.8.1-SNAPSHOT + 2.8.2-SNAPSHOT 1.2.0 UTF-8 21 @@ -38,7 +38,7 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots @@ -51,7 +51,7 @@ sonatype-nexus-snapshots Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots false diff --git a/frameworks/Java/redkale/redkale-jdbc.dockerfile b/frameworks/Java/redkale/redkale-jdbc.dockerfile index ac3a85bec8b..445d8381b02 100644 --- a/frameworks/Java/redkale/redkale-jdbc.dockerfile +++ b/frameworks/Java/redkale/redkale-jdbc.dockerfile @@ -5,11 +5,11 @@ COPY conf conf COPY pom-jdbc.xml pom.xml RUN mvn package -q -FROM openjdk:23-jdk-slim +FROM azul/zulu-openjdk:25 WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar EXPOSE 8080 -CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+UseCompactObjectHeaders", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file diff --git a/frameworks/Java/redkale/redkale-native.dockerfile b/frameworks/Java/redkale/redkale-native.dockerfile index 56fa1921f96..00c19b11a6a 100644 --- a/frameworks/Java/redkale/redkale-native.dockerfile +++ b/frameworks/Java/redkale/redkale-native.dockerfile @@ -6,13 +6,13 @@ COPY pom.xml pom.xml RUN mvn package -q -FROM ghcr.io/graalvm/native-image-community:22.0.2 as native +FROM ghcr.io/graalvm/native-image-community:25.0.0 as native WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar RUN native-image -H:+ReportExceptionStackTraces --report-unsupported-elements-at-runtime -jar redkale-benchmark.jar -FROM ghcr.io/graalvm/jdk-community:22.0.2 +FROM ghcr.io/graalvm/jdk-community:25.0.0 WORKDIR /redkale COPY --from=native /redkale/redkale-benchmark redkale-benchmark diff --git a/frameworks/Java/redkale/redkale-pgclient.dockerfile b/frameworks/Java/redkale/redkale-pgclient.dockerfile index 761368ba604..167d62d4808 100644 --- a/frameworks/Java/redkale/redkale-pgclient.dockerfile +++ b/frameworks/Java/redkale/redkale-pgclient.dockerfile @@ -5,11 +5,11 @@ COPY conf conf COPY pom-pgclient.xml pom.xml RUN mvn package -q -FROM openjdk:23-jdk-slim +FROM eclipse-temurin:25-jre-noble WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar EXPOSE 8080 -CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dvertx.disableURIValidation=true", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+UseCompactObjectHeaders", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dvertx.disableURIValidation=true", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file diff --git a/frameworks/Java/redkale/redkale.dockerfile b/frameworks/Java/redkale/redkale.dockerfile index 79ec585c205..06936406e29 100644 --- a/frameworks/Java/redkale/redkale.dockerfile +++ b/frameworks/Java/redkale/redkale.dockerfile @@ -5,11 +5,11 @@ COPY conf conf COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:23-jdk-slim +FROM azul/zulu-openjdk:25 WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar EXPOSE 8080 -CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+UseCompactObjectHeaders", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] diff --git a/frameworks/Java/servlet/benchmark_config.json b/frameworks/Java/servlet/benchmark_config.json index 527e2bd008b..cb198156b11 100644 --- a/frameworks/Java/servlet/benchmark_config.json +++ b/frameworks/Java/servlet/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "servlet", "notes": "", - "versus": "servlet" + "versus": "" }, "lib-native": { "json_url": "/json", diff --git a/frameworks/Java/servlet/config.toml b/frameworks/Java/servlet/config.toml index 47d7231c79a..b0e45dc189e 100644 --- a/frameworks/Java/servlet/config.toml +++ b/frameworks/Java/servlet/config.toml @@ -12,7 +12,7 @@ os = "Linux" orm = "Raw" platform = "Servlet" webserver = "Resin" -versus = "servlet" +versus = "" [lib-native] urls.plaintext = "/plaintext" diff --git a/frameworks/Java/simple-server/pom.xml b/frameworks/Java/simple-server/pom.xml index 807c5a9a4b2..19a4b6084ff 100644 --- a/frameworks/Java/simple-server/pom.xml +++ b/frameworks/Java/simple-server/pom.xml @@ -27,7 +27,7 @@ 1.18.4 - 2.17.1 + 2.25.3 diff --git a/frameworks/Java/smart-socket/pom.xml b/frameworks/Java/smart-socket/pom.xml index 171f036e654..be5528246c9 100644 --- a/frameworks/Java/smart-socket/pom.xml +++ b/frameworks/Java/smart-socket/pom.xml @@ -20,7 +20,7 @@ tech.smartboot.feat feat-cloud-starter - 1.3.2-SNAPSHOT + 1.4.0 diff --git a/frameworks/Java/solon/benchmark_config.json b/frameworks/Java/solon/benchmark_config.json index 52c9fd8be8c..c1818edd596 100644 --- a/frameworks/Java/solon/benchmark_config.json +++ b/frameworks/Java/solon/benchmark_config.json @@ -19,7 +19,8 @@ "database_os": "Linux", "display_name": "solon", "notes": "", - "versus": "None" + "versus": "None", + "tags": ["broken"] } } ] diff --git a/frameworks/Java/spring/README.md b/frameworks/Java/spring/README.md index 742649fff7e..d2dc5e3cb87 100644 --- a/frameworks/Java/spring/README.md +++ b/frameworks/Java/spring/README.md @@ -4,8 +4,10 @@ This is the Spring MVC portion of a [benchmarking test suite](../) comparing a v An embedded undertow is used for the web server. -There are two implementations : +There are four implementations : * For postgresql access, JdbcTemplate is used. See [JdbcDbRepository](src/main/java/hello/JdbcDbRepository.java). +* For postgresql access, Spring Data JDBC is used. See [DataJdbcDbRepository](src/main/java/hello/DataJdbcDbRepository.java). +* For postgresql access, jOOQ is used. See [JooqDbRepository](src/main/java/hello/JooqDbRepository.java). * For mongoDB access, MongoTemplate is used. See [MongoDbRepository](src/main/java/hello/MongoDbRepository.java). ### Plaintext Test @@ -62,3 +64,19 @@ There are two implementations : ### Template rendering Test http://localhost:8080/fortunes + +## Build + +### jOOQ + +The jOOQ version requires Java classes generated from the database schema into +`src/main/jooq/hello/db`. In order to generate them, you need to run a postgresql container and +then execute the Maven `jooq-codegen:generate` command: + +```bash +(../../../toolset/databases/postgres && docker run -p 5432:5432 --rm "$(docker build -q -f postgres.dockerfile .)") +``` + +```bash +mvn jooq-codegen:generate +``` diff --git a/frameworks/Java/spring/benchmark_config.json b/frameworks/Java/spring/benchmark_config.json index 72362984811..2a38964f019 100644 --- a/frameworks/Java/spring/benchmark_config.json +++ b/frameworks/Java/spring/benchmark_config.json @@ -24,6 +24,52 @@ "notes": "", "versus": "" }, + "data-jdbc": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "spring", + "language": "Java", + "flavor": "None", + "orm": "Full", + "platform": "Servlet", + "webserver": "Undertow", + "os": "Linux", + "database_os": "Linux", + "display_name": "spring-data-jdbc", + "notes": "", + "versus": "" + }, + "jooq": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "spring", + "language": "Java", + "flavor": "None", + "orm": "Full", + "platform": "Servlet", + "webserver": "Undertow", + "os": "Linux", + "database_os": "Linux", + "display_name": "spring-jooq", + "notes": "", + "versus": "" + }, "mongo": { "db_url": "/db", "query_url": "/queries?queries=", diff --git a/frameworks/Java/spring/pom.xml b/frameworks/Java/spring/pom.xml index 3271ab04f03..6a5b0e32b31 100644 --- a/frameworks/Java/spring/pom.xml +++ b/frameworks/Java/spring/pom.xml @@ -38,6 +38,14 @@ org.springframework.boot spring-boot-starter-jdbc + + org.springframework.boot + spring-boot-starter-data-jdbc + + + org.springframework.boot + spring-boot-starter-jooq + org.springframework.boot spring-boot-starter-data-mongodb @@ -80,6 +88,58 @@ + + org.jooq + jooq-codegen-maven + + + + org.postgresql + postgresql + 42.7.3 + + + + + + org.postgresql.Driver + jdbc:postgresql://localhost:5432/hello_world + benchmarkdbuser + benchmarkdbpass + + + + org.jooq.meta.postgres.PostgresDatabase + .* + pg_stat.* + public + + + hello.db + src/main/jooq + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.0 + + + add-jooq-sources + generate-sources + + add-source + + + + src/main/jooq + + + + + diff --git a/frameworks/Java/spring/spring-data-jdbc.dockerfile b/frameworks/Java/spring/spring-data-jdbc.dockerfile new file mode 100644 index 00000000000..8e3b1e42dc6 --- /dev/null +++ b/frameworks/Java/spring/spring-data-jdbc.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.9.5-eclipse-temurin-21 AS maven +WORKDIR /spring +COPY src src +COPY pom.xml pom.xml +RUN mvn package -q + +FROM bellsoft/liberica-openjre-debian:23 +WORKDIR /spring +COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract + +EXPOSE 8080 + +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=data-jdbc"] \ No newline at end of file diff --git a/frameworks/Java/spring/spring-jooq.dockerfile b/frameworks/Java/spring/spring-jooq.dockerfile new file mode 100644 index 00000000000..d9ad2be1b48 --- /dev/null +++ b/frameworks/Java/spring/spring-jooq.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.9.5-eclipse-temurin-21 AS maven +WORKDIR /spring +COPY src src +COPY pom.xml pom.xml +RUN mvn package -q + +FROM bellsoft/liberica-openjre-debian:23 +WORKDIR /spring +COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar +# See https://docs.spring.io/spring-boot/reference/packaging/efficient.html +RUN java -Djarmode=tools -jar app.jar extract + +EXPOSE 8080 + +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jooq"] \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/DataJdbcConfig.java b/frameworks/Java/spring/src/main/java/hello/DataJdbcConfig.java new file mode 100644 index 00000000000..e43510aebb6 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/DataJdbcConfig.java @@ -0,0 +1,12 @@ +package hello; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; + +@Profile("data-jdbc") +@Configuration +@EnableJdbcRepositories(basePackages = "hello.repository") +public class DataJdbcConfig { + +} diff --git a/frameworks/Java/spring/src/main/java/hello/JooqConfig.java b/frameworks/Java/spring/src/main/java/hello/JooqConfig.java new file mode 100644 index 00000000000..a6fbd4cf5a4 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/JooqConfig.java @@ -0,0 +1,13 @@ +package hello; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Profile("jooq") +@Configuration +@EnableAutoConfiguration(exclude = { JdbcRepositoriesAutoConfiguration.class }) +public class JooqConfig { + +} diff --git a/frameworks/Java/spring/src/main/java/hello/model/Fortune.java b/frameworks/Java/spring/src/main/java/hello/model/Fortune.java index a628d3c755f..62fbe353701 100644 --- a/frameworks/Java/spring/src/main/java/hello/model/Fortune.java +++ b/frameworks/Java/spring/src/main/java/hello/model/Fortune.java @@ -3,8 +3,10 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.data.relational.core.mapping.Table; @Document +@Table public final class Fortune implements Comparable{ @Id diff --git a/frameworks/Java/spring/src/main/java/hello/model/World.java b/frameworks/Java/spring/src/main/java/hello/model/World.java index 762e9e622ce..180f6bfa590 100644 --- a/frameworks/Java/spring/src/main/java/hello/model/World.java +++ b/frameworks/Java/spring/src/main/java/hello/model/World.java @@ -3,14 +3,18 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; @Document +@Table public final class World { @Id public int id; @Field("randomNumber") + @Column("randomnumber") public int randomNumber; diff --git a/frameworks/Java/spring/src/main/java/hello/repository/DataJdbcDbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/DataJdbcDbRepository.java new file mode 100644 index 00000000000..e633c0860a6 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/repository/DataJdbcDbRepository.java @@ -0,0 +1,38 @@ +package hello.repository; + +import java.util.List; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import hello.model.Fortune; +import hello.model.World; + +@Repository +@Profile("data-jdbc") +public class DataJdbcDbRepository implements DbRepository { + + private WorldDataJdbcRepository worldDataJdbcRepository; + private FortuneDataJdbcRepository fortuneDataJdbcRepository; + + public DataJdbcDbRepository(WorldDataJdbcRepository worldDataJdbcRepository, FortuneDataJdbcRepository fortuneDataJdbcRepository) { + this.worldDataJdbcRepository = worldDataJdbcRepository; + this.fortuneDataJdbcRepository = fortuneDataJdbcRepository; + } + + @Override + public World getWorld(int id) { + return worldDataJdbcRepository.findById(id).orElse(null); + } + + @Override + public void updateWorlds(List worlds) { + worldDataJdbcRepository.saveAll(worlds); + } + + @Override + public List fortunes() { + return fortuneDataJdbcRepository.findAll(); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/repository/FortuneDataJdbcRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/FortuneDataJdbcRepository.java new file mode 100644 index 00000000000..31f888bedf2 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/repository/FortuneDataJdbcRepository.java @@ -0,0 +1,11 @@ +package hello.repository; + +import org.springframework.data.repository.ListCrudRepository; +import org.springframework.stereotype.Repository; + +import hello.model.Fortune; + +@Repository +interface FortuneDataJdbcRepository extends ListCrudRepository { + +} \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/repository/JooqDbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/JooqDbRepository.java new file mode 100644 index 00000000000..27be3a12518 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/repository/JooqDbRepository.java @@ -0,0 +1,41 @@ +package hello.repository; + +import static hello.db.tables.Fortune.FORTUNE; +import static hello.db.tables.World.WORLD; + +import java.util.List; + +import org.jooq.DSLContext; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import hello.db.tables.records.WorldRecord; +import hello.model.Fortune; +import hello.model.World; + +@Repository +@Profile("jooq") +public class JooqDbRepository implements DbRepository { + + private DSLContext dslContext; + + public JooqDbRepository(DSLContext dslContext) { + this.dslContext = dslContext; + } + + @Override + public World getWorld(int id) { + return dslContext.selectFrom(WORLD).where(WORLD.ID.eq(id)).fetchOneInto(World.class); + } + + @Override + public void updateWorlds(List worlds) { + dslContext.batchUpdate(worlds.stream().map(it -> new WorldRecord(it.id, it.randomNumber)).toList()).execute(); + } + + @Override + public List fortunes() { + return dslContext.selectFrom(FORTUNE).fetchInto(Fortune.class); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java index 9b6b67c4c95..1872609d875 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java @@ -1,6 +1,5 @@ package hello.repository; -import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Profile; @@ -11,8 +10,6 @@ import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; -import com.mongodb.bulk.BulkWriteResult; -import hello.Utils; import hello.model.Fortune; import hello.model.World; diff --git a/frameworks/Java/spring/src/main/java/hello/repository/WorldDataJdbcRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/WorldDataJdbcRepository.java new file mode 100644 index 00000000000..9e4ba30b9fa --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/repository/WorldDataJdbcRepository.java @@ -0,0 +1,11 @@ +package hello.repository; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import hello.model.World; + +@Repository +interface WorldDataJdbcRepository extends CrudRepository { + +} \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/DefaultCatalog.java b/frameworks/Java/spring/src/main/jooq/hello/db/DefaultCatalog.java new file mode 100644 index 00000000000..9abad40df03 --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/DefaultCatalog.java @@ -0,0 +1,54 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db; + + +import java.util.Arrays; +import java.util.List; + +import org.jooq.Constants; +import org.jooq.Schema; +import org.jooq.impl.CatalogImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class DefaultCatalog extends CatalogImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of DEFAULT_CATALOG + */ + public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog(); + + /** + * The schema public. + */ + public final Public PUBLIC = Public.PUBLIC; + + /** + * No further instances allowed + */ + private DefaultCatalog() { + super(""); + } + + @Override + public final List getSchemas() { + return Arrays.asList( + Public.PUBLIC + ); + } + + /** + * A reference to the 3.19 minor release of the code generator. If this + * doesn't compile, it's because the runtime library uses an older minor + * release, namely: 3.19. You can turn off the generation of this reference + * by specifying /configuration/generator/generate/jooqVersionReference + */ + private static final String REQUIRE_RUNTIME_JOOQ_VERSION = Constants.VERSION_3_19; +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/Keys.java b/frameworks/Java/spring/src/main/jooq/hello/db/Keys.java new file mode 100644 index 00000000000..f21e0d9d300 --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/Keys.java @@ -0,0 +1,31 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db; + + +import hello.db.tables.Fortune; +import hello.db.tables.World; +import hello.db.tables.records.FortuneRecord; +import hello.db.tables.records.WorldRecord; + +import org.jooq.TableField; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.Internal; + + +/** + * A class modelling foreign key relationships and constraints of tables in + * public. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class Keys { + + // ------------------------------------------------------------------------- + // UNIQUE and PRIMARY KEY definitions + // ------------------------------------------------------------------------- + + public static final UniqueKey FORTUNE_PKEY = Internal.createUniqueKey(Fortune.FORTUNE, DSL.name("Fortune_pkey"), new TableField[] { Fortune.FORTUNE.ID }, true); + public static final UniqueKey WORLD_PKEY = Internal.createUniqueKey(World.WORLD, DSL.name("World_pkey"), new TableField[] { World.WORLD.ID }, true); +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/Public.java b/frameworks/Java/spring/src/main/jooq/hello/db/Public.java new file mode 100644 index 00000000000..40cd2a02ffe --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/Public.java @@ -0,0 +1,61 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db; + + +import hello.db.tables.Fortune; +import hello.db.tables.World; + +import java.util.Arrays; +import java.util.List; + +import org.jooq.Catalog; +import org.jooq.Table; +import org.jooq.impl.SchemaImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class Public extends SchemaImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of public + */ + public static final Public PUBLIC = new Public(); + + /** + * The table public.Fortune. + */ + public final Fortune FORTUNE = Fortune.FORTUNE; + + /** + * The table public.World. + */ + public final World WORLD = World.WORLD; + + /** + * No further instances allowed + */ + private Public() { + super("public", null); + } + + + @Override + public Catalog getCatalog() { + return DefaultCatalog.DEFAULT_CATALOG; + } + + @Override + public final List> getTables() { + return Arrays.asList( + Fortune.FORTUNE, + World.WORLD + ); + } +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/Tables.java b/frameworks/Java/spring/src/main/jooq/hello/db/Tables.java new file mode 100644 index 00000000000..2425d662374 --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/Tables.java @@ -0,0 +1,26 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db; + + +import hello.db.tables.Fortune; +import hello.db.tables.World; + + +/** + * Convenience access to all tables in public. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class Tables { + + /** + * The table public.Fortune. + */ + public static final Fortune FORTUNE = Fortune.FORTUNE; + + /** + * The table public.World. + */ + public static final World WORLD = World.WORLD; +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/tables/Fortune.java b/frameworks/Java/spring/src/main/jooq/hello/db/tables/Fortune.java new file mode 100644 index 00000000000..8225712727d --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/tables/Fortune.java @@ -0,0 +1,223 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db.tables; + + +import hello.db.Keys; +import hello.db.Public; +import hello.db.tables.records.FortuneRecord; + +import java.util.Collection; + +import org.jooq.Condition; +import org.jooq.Field; +import org.jooq.Name; +import org.jooq.PlainSQL; +import org.jooq.QueryPart; +import org.jooq.SQL; +import org.jooq.Schema; +import org.jooq.Select; +import org.jooq.Stringly; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.SQLDataType; +import org.jooq.impl.TableImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class Fortune extends TableImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of public.Fortune + */ + public static final Fortune FORTUNE = new Fortune(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return FortuneRecord.class; + } + + /** + * The column public.Fortune.id. + */ + public final TableField ID = createField(DSL.name("id"), SQLDataType.INTEGER.nullable(false), this, ""); + + /** + * The column public.Fortune.message. + */ + public final TableField MESSAGE = createField(DSL.name("message"), SQLDataType.VARCHAR(2048).nullable(false), this, ""); + + private Fortune(Name alias, Table aliased) { + this(alias, aliased, (Field[]) null, null); + } + + private Fortune(Name alias, Table aliased, Field[] parameters, Condition where) { + super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where); + } + + /** + * Create an aliased public.Fortune table reference + */ + public Fortune(String alias) { + this(DSL.name(alias), FORTUNE); + } + + /** + * Create an aliased public.Fortune table reference + */ + public Fortune(Name alias) { + this(alias, FORTUNE); + } + + /** + * Create a public.Fortune table reference + */ + public Fortune() { + this(DSL.name("Fortune"), null); + } + + @Override + public Schema getSchema() { + return aliased() ? null : Public.PUBLIC; + } + + @Override + public UniqueKey getPrimaryKey() { + return Keys.FORTUNE_PKEY; + } + + @Override + public Fortune as(String alias) { + return new Fortune(DSL.name(alias), this); + } + + @Override + public Fortune as(Name alias) { + return new Fortune(alias, this); + } + + @Override + public Fortune as(Table alias) { + return new Fortune(alias.getQualifiedName(), this); + } + + /** + * Rename this table + */ + @Override + public Fortune rename(String name) { + return new Fortune(DSL.name(name), null); + } + + /** + * Rename this table + */ + @Override + public Fortune rename(Name name) { + return new Fortune(name, null); + } + + /** + * Rename this table + */ + @Override + public Fortune rename(Table name) { + return new Fortune(name.getQualifiedName(), null); + } + + /** + * Create an inline derived table from this table + */ + @Override + public Fortune where(Condition condition) { + return new Fortune(getQualifiedName(), aliased() ? this : null, null, condition); + } + + /** + * Create an inline derived table from this table + */ + @Override + public Fortune where(Collection conditions) { + return where(DSL.and(conditions)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public Fortune where(Condition... conditions) { + return where(DSL.and(conditions)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public Fortune where(Field condition) { + return where(DSL.condition(condition)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public Fortune where(SQL condition) { + return where(DSL.condition(condition)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public Fortune where(@Stringly.SQL String condition) { + return where(DSL.condition(condition)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public Fortune where(@Stringly.SQL String condition, Object... binds) { + return where(DSL.condition(condition, binds)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public Fortune where(@Stringly.SQL String condition, QueryPart... parts) { + return where(DSL.condition(condition, parts)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public Fortune whereExists(Select select) { + return where(DSL.exists(select)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public Fortune whereNotExists(Select select) { + return where(DSL.notExists(select)); + } +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/tables/World.java b/frameworks/Java/spring/src/main/jooq/hello/db/tables/World.java new file mode 100644 index 00000000000..56df4cbc66c --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/tables/World.java @@ -0,0 +1,223 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db.tables; + + +import hello.db.Keys; +import hello.db.Public; +import hello.db.tables.records.WorldRecord; + +import java.util.Collection; + +import org.jooq.Condition; +import org.jooq.Field; +import org.jooq.Name; +import org.jooq.PlainSQL; +import org.jooq.QueryPart; +import org.jooq.SQL; +import org.jooq.Schema; +import org.jooq.Select; +import org.jooq.Stringly; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.SQLDataType; +import org.jooq.impl.TableImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class World extends TableImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of public.World + */ + public static final World WORLD = new World(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return WorldRecord.class; + } + + /** + * The column public.World.id. + */ + public final TableField ID = createField(DSL.name("id"), SQLDataType.INTEGER.nullable(false), this, ""); + + /** + * The column public.World.randomnumber. + */ + public final TableField RANDOMNUMBER = createField(DSL.name("randomnumber"), SQLDataType.INTEGER.nullable(false).defaultValue(DSL.field(DSL.raw("0"), SQLDataType.INTEGER)), this, ""); + + private World(Name alias, Table aliased) { + this(alias, aliased, (Field[]) null, null); + } + + private World(Name alias, Table aliased, Field[] parameters, Condition where) { + super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where); + } + + /** + * Create an aliased public.World table reference + */ + public World(String alias) { + this(DSL.name(alias), WORLD); + } + + /** + * Create an aliased public.World table reference + */ + public World(Name alias) { + this(alias, WORLD); + } + + /** + * Create a public.World table reference + */ + public World() { + this(DSL.name("World"), null); + } + + @Override + public Schema getSchema() { + return aliased() ? null : Public.PUBLIC; + } + + @Override + public UniqueKey getPrimaryKey() { + return Keys.WORLD_PKEY; + } + + @Override + public World as(String alias) { + return new World(DSL.name(alias), this); + } + + @Override + public World as(Name alias) { + return new World(alias, this); + } + + @Override + public World as(Table alias) { + return new World(alias.getQualifiedName(), this); + } + + /** + * Rename this table + */ + @Override + public World rename(String name) { + return new World(DSL.name(name), null); + } + + /** + * Rename this table + */ + @Override + public World rename(Name name) { + return new World(name, null); + } + + /** + * Rename this table + */ + @Override + public World rename(Table name) { + return new World(name.getQualifiedName(), null); + } + + /** + * Create an inline derived table from this table + */ + @Override + public World where(Condition condition) { + return new World(getQualifiedName(), aliased() ? this : null, null, condition); + } + + /** + * Create an inline derived table from this table + */ + @Override + public World where(Collection conditions) { + return where(DSL.and(conditions)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public World where(Condition... conditions) { + return where(DSL.and(conditions)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public World where(Field condition) { + return where(DSL.condition(condition)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public World where(SQL condition) { + return where(DSL.condition(condition)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public World where(@Stringly.SQL String condition) { + return where(DSL.condition(condition)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public World where(@Stringly.SQL String condition, Object... binds) { + return where(DSL.condition(condition, binds)); + } + + /** + * Create an inline derived table from this table + */ + @Override + @PlainSQL + public World where(@Stringly.SQL String condition, QueryPart... parts) { + return where(DSL.condition(condition, parts)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public World whereExists(Select select) { + return where(DSL.exists(select)); + } + + /** + * Create an inline derived table from this table + */ + @Override + public World whereNotExists(Select select) { + return where(DSL.notExists(select)); + } +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/tables/records/FortuneRecord.java b/frameworks/Java/spring/src/main/jooq/hello/db/tables/records/FortuneRecord.java new file mode 100644 index 00000000000..f8fe3d871ea --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/tables/records/FortuneRecord.java @@ -0,0 +1,79 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db.tables.records; + + +import hello.db.tables.Fortune; + +import org.jooq.Record1; +import org.jooq.impl.UpdatableRecordImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class FortuneRecord extends UpdatableRecordImpl { + + private static final long serialVersionUID = 1L; + + /** + * Setter for public.Fortune.id. + */ + public void setId(Integer value) { + set(0, value); + } + + /** + * Getter for public.Fortune.id. + */ + public Integer getId() { + return (Integer) get(0); + } + + /** + * Setter for public.Fortune.message. + */ + public void setMessage(String value) { + set(1, value); + } + + /** + * Getter for public.Fortune.message. + */ + public String getMessage() { + return (String) get(1); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached FortuneRecord + */ + public FortuneRecord() { + super(Fortune.FORTUNE); + } + + /** + * Create a detached, initialised FortuneRecord + */ + public FortuneRecord(Integer id, String message) { + super(Fortune.FORTUNE); + + setId(id); + setMessage(message); + resetChangedOnNotNull(); + } +} diff --git a/frameworks/Java/spring/src/main/jooq/hello/db/tables/records/WorldRecord.java b/frameworks/Java/spring/src/main/jooq/hello/db/tables/records/WorldRecord.java new file mode 100644 index 00000000000..ffa764a3b61 --- /dev/null +++ b/frameworks/Java/spring/src/main/jooq/hello/db/tables/records/WorldRecord.java @@ -0,0 +1,79 @@ +/* + * This file is generated by jOOQ. + */ +package hello.db.tables.records; + + +import hello.db.tables.World; + +import org.jooq.Record1; +import org.jooq.impl.UpdatableRecordImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) +public class WorldRecord extends UpdatableRecordImpl { + + private static final long serialVersionUID = 1L; + + /** + * Setter for public.World.id. + */ + public void setId(Integer value) { + set(0, value); + } + + /** + * Getter for public.World.id. + */ + public Integer getId() { + return (Integer) get(0); + } + + /** + * Setter for public.World.randomnumber. + */ + public void setRandomnumber(Integer value) { + set(1, value); + } + + /** + * Getter for public.World.randomnumber. + */ + public Integer getRandomnumber() { + return (Integer) get(1); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached WorldRecord + */ + public WorldRecord() { + super(World.WORLD); + } + + /** + * Create a detached, initialised WorldRecord + */ + public WorldRecord(Integer id, Integer randomnumber) { + super(World.WORLD); + + setId(id); + setRandomnumber(randomnumber); + resetChangedOnNotNull(); + } +} diff --git a/frameworks/Java/spring/src/main/resources/application.yml b/frameworks/Java/spring/src/main/resources/application.yml index efde83cda61..bfebe396371 100644 --- a/frameworks/Java/spring/src/main/resources/application.yml +++ b/frameworks/Java/spring/src/main/resources/application.yml @@ -7,7 +7,7 @@ server: spring: config: activate: - on-profile: jdbc + on-profile: jdbc | data-jdbc | jooq autoconfigure: exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration datasource: @@ -32,9 +32,7 @@ spring: exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration spring.data.mongodb: - host: tfb-database - port: 27017 - database: hello_world + uri: mongodb://tfb-database:27017/hello_world?maxPoolSize=256 --- spring: diff --git a/frameworks/Java/tadx/README.cn.md b/frameworks/Java/tadx/README.cn.md new file mode 100644 index 00000000000..e099c71564f --- /dev/null +++ b/frameworks/Java/tadx/README.cn.md @@ -0,0 +1,108 @@ +# Tad.x (tadx) 基准测试 + +## 项目概述 +Tad.x 是一个用于基准测试的 Java Web 框架项目,是 [FrameworkBenchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) 的一部分,主要用于测试不同 Web 框架的性能表现。 + +## 技术栈 +- **Java 21**:项目的主要开发语言 +- **Spring Boot**:当前使用的主要框架(从代码中可以看到之前可能使用过 Vert.x,现已注释) +- **Vert.x**:用于异步事件处理和数据库操作 +- **PostgreSQL**:基准测试使用的数据库 +- **Thymeleaf & FreeMarker**:模板引擎,用于Fortunes测试 +- **Gradle**:项目构建工具 + +## 项目结构 +```yaml +tadx/ +├── src/main/java/io/tadx/benchmark/ +│ ├── Application.java # Project entry point +│ ├── controller/ # Controller classes +│ ├── entity/ # Database entity classes +│ └── route_mapper/ # Route mapping implementations +├── src/main/resources/ # Resource files +│ ├── application.yaml # Configuration file +│ └── templates/ # Template files +├── build.gradle # Gradle build configuration +├── settings.gradle # Gradle settings +└── tadx.dockerfile # Docker deployment configuration +``` + +## 核心功能 +项目实现了以下基准测试类型: + +| 测试类型 | 路由 | 实现类 | 功能描述 | +|---------|------|-------|----------| +| JSON | /json | JsonRouteMapper.java | 返回简单JSON响应 | +| 文本 | /plaintext | PlainTextRouteMapper.java | 返回简单文本响应 | +| 数据库 | /db | DbRouteMapper_Postgresql.java | 单条数据库查询 | +| 多查询 | /query | QueriesRouteMapper1_Postgresql.java | 多条数据库查询 | +| 缓存查询 | /cached_query | CachedQueriesMapper3.java | 缓存查询结果 | +| 更新 | /update | UpdateMapper.java | 数据库更新操作 | +| 幸运饼干 | /fortunes | FortunesRouteMapper1.java | 模板渲染测试 | + +## 实现特点 + +### 路由机制 +- 使用自定义的 `@RouteMapping` 注解定义路由 +- 每个测试类型对应一个 `RouteMapper` 接口实现 +- 路由处理直接操作 Vert.x 的响应对象,减少中间层开销 + +### 数据库操作 +- 使用 Vert.x 的 PostgreSQL 客户端进行异步数据库操作 +- 配置了数据库连接池,最大连接数为 2000 +- 支持 prepared statements 缓存,提高性能 +- 定义了 `World` 和 `Fortune` 两个实体类映射数据库表 + +### 性能优化 +- 直接设置 HTTP 响应头和状态码,减少框架开销 +- 使用预编译语句和连接池提高数据库性能 +- 缓存常用的响应头和日期字符串 + +## 运行方式 +1. **直接运行**:通过 `Application.java` 的 main 方法启动 Spring Boot 应用 +2. **构建运行**:使用 Gradle 构建 JAR 文件后运行 +3. **Docker部署**:使用提供的 tadx.dockerfile 构建镜像并运行 + +## 配置文件 +- `application.yaml`:Spring Boot 应用配置 +- `benchmark_config.json`:基准测试配置 + +## 测试类型实现源代码 + +* [JSON](src/main/java/io/tadx/benchmark/route_mapper/JsonRouteMapper.java) +* [PLAINTEXT](src/main/java/io/tadx/benchmark/route_mapper/PlainTextRouteMapper.java) +* [DB](src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Postgresql.java) +* [QUERY](src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper1_Postgresql.java) +* [CACHED QUERY](src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper3.java) +* [UPDATE](src/main/java/io/tadx/benchmark/route_mapper/UpdateMapper.java) +* [FORTUNES](src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper1.java) + + +## 测试URLs +### JSON + +http://localhost:8000/json + +### PLAINTEXT + +http://localhost:8000/plaintext + +### DB + +http://localhost:8000/db + +### QUERY + +http://localhost:8000/query?queries= + +### CACHED QUERY + +http://localhost:8000/cached_query?queries= + +### UPDATE + +http://localhost:8000/update?queries= + +### FORTUNES + +http://localhost:8000/fortunes diff --git a/frameworks/Java/tadx/README.en.md b/frameworks/Java/tadx/README.en.md new file mode 100644 index 00000000000..585637f6828 --- /dev/null +++ b/frameworks/Java/tadx/README.en.md @@ -0,0 +1,111 @@ +# Tad.x (tadx) Benchmarking Test + +## Project Overview +Tad.x is a Java web framework project for benchmarking, part of the [FrameworkBenchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) project, designed to test the performance of different web frameworks. + +## Technology Stack +- **Java 21**: The primary development language +- **Spring Boot**: The main framework currently used (previously used Vert.x, now commented out) +- **Vert.x**: For asynchronous event handling and database operations +- **PostgreSQL**: Database used for benchmarking +- **Thymeleaf & FreeMarker**: Template engines for the Fortunes test +- **Gradle**: Project build tool + +## Project Structure +```yaml +tadx/ +├── src/main/java/io/tadx/benchmark/ +│ ├── Application.java # Project entry point +│ ├── controller/ # Controller classes +│ ├── entity/ # Database entity classes +│ └── route_mapper/ # Route mapping implementations +├── src/main/resources/ # Resource files +│ ├── application.yaml # Configuration file +│ └── templates/ # Template files +├── build.gradle # Gradle build configuration +├── settings.gradle # Gradle settings +└── tadx.dockerfile # Docker deployment configuration +``` + + +plainText + +## Core Features +The project implements the following benchmark test types: + +| Test Type | Route | Implementation Class | Description | +|---------|------|-------|----------| +| JSON | /json | JsonRouteMapper.java | Returns a simple JSON response | +| PLAINTEXT | /plaintext | PlainTextRouteMapper.java | Returns a simple text response | +| DB | /db | DbRouteMapper_Postgresql.java | Single database query | +| QUERY | /query | QueriesRouteMapper1_Postgresql.java | Multiple database queries | +| CACHED QUERY | /cached_query | CachedQueriesMapper3.java | Caches query results | +| UPDATE | /update | UpdateMapper.java | Database update operations | +| FORTUNES | /fortunes | FortunesRouteMapper1.java | Template rendering test | + +## Implementation Features + +### Routing Mechanism +- Uses custom `@RouteMapping` annotation to define routes +- Each test type corresponds to a `RouteMapper` interface implementation +- Route handling directly manipulates Vert.x response objects to reduce overhead + +### Database Operations +- Uses Vert.x PostgreSQL client for asynchronous database operations +- Configures database connection pool with maximum 2000 connections +- Supports prepared statements caching for improved performance +- Defines `World` and `Fortune` entity classes mapping to database tables + +### Performance Optimization +- Directly sets HTTP response headers and status codes to reduce framework overhead +- Uses precompiled statements and connection pooling to improve database performance +- Caches commonly used response headers and date strings + +## Running Methods +1. **Direct Run**: Start the Spring Boot application through the main method in `Application.java` +2. **Build and Run**: Build JAR file using Gradle and run it +3. **Docker Deployment**: Build image using the provided tadx.dockerfile and run it + +## Configuration Files +- `application.yaml`: Spring Boot application configuration +- `benchmark_config.json`: Benchmark configuration + +## Test Type Implementation Source Code + +* [JSON](src/main/java/io/tadx/benchmark/route_mapper/JsonRouteMapper.java) +* [PLAINTEXT](src/main/java/io/tadx/benchmark/route_mapper/PlainTextRouteMapper.java) +* [DB](src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Postgresql.java) +* [QUERY](src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper1_Postgresql.java) +* [CACHED QUERY](src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper3.java) +* [UPDATE](src/main/java/io/tadx/benchmark/route_mapper/UpdateMapper.java) +* [FORTUNES](src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper1.java) + + +## Test URLs +### JSON + +http://localhost:8000/json + +### PLAINTEXT + +http://localhost:8000/plaintext + +### DB + +http://localhost:8000/db + +### QUERY + +http://localhost:8000/query?queries= + +### CACHED QUERY + +http://localhost:8000/cached_query?queries= + +### UPDATE + +http://localhost:8000/update?queries= + +### FORTUNES + +http://localhost:8000/fortunes \ No newline at end of file diff --git a/frameworks/Java/tadx/README.md b/frameworks/Java/tadx/README.md new file mode 100644 index 00000000000..26236b975c2 --- /dev/null +++ b/frameworks/Java/tadx/README.md @@ -0,0 +1,11 @@ +# Tad.x (tadx) Benchmarking Test / Tad.x (tadx) 基准测试 + +## Project Overview / 项目概述 +Tad.x is a Java web framework project for benchmarking, part of the [FrameworkBenchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) project, designed to test the performance of different web frameworks. + +Tad.x 是一个用于基准测试的 Java Web 框架项目,是 [FrameworkBenchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) 的一部分,主要用于测试不同 Web 框架的性能表现。 + + +## Detailed Documentation / 详细文档 +- [English Version](README.en.md) / [英文版本](README.en.md) +- [Chinese Version](README.cn.md) / [中文版本](README.cn.md) diff --git a/frameworks/Java/tadx/benchmark_config.json b/frameworks/Java/tadx/benchmark_config.json new file mode 100644 index 00000000000..3a2cd6644df --- /dev/null +++ b/frameworks/Java/tadx/benchmark_config.json @@ -0,0 +1,32 @@ +{ + "framework": "tadx", + "maintainers": ["yn-tadpole"], + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/update?queries=", + "cached_query_url" : "/cached_queries?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "Tad.x", + "language": "Java", + "flavor": "None", + "orm": "Micro", + "platform": "Tad.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "tadx", + "notes": "", + "versus": "" + } + } + ] +} diff --git a/frameworks/Java/tadx/build.gradle b/frameworks/Java/tadx/build.gradle new file mode 100644 index 00000000000..444ac710eeb --- /dev/null +++ b/frameworks/Java/tadx/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.5.5' +} + +group = 'io.tadx.benchmark' +version = '0.0.1-SNAPSHOT' +description = 'Tad.x Framework Benchmark project' + +repositories { + mavenLocal() + maven {url 'https://maven.aliyun.com/repository/public'} + maven {url 'https://maven.aliyun.com/repository/spring'} + maven {url 'https://maven.aliyun.com/repository/spring-plugin'} + mavenCentral() +} + +dependencies { + implementation project(':tadx-web') + implementation project(':tadx-data') + implementation('io.vertx:vertx-jdbc-client:5.0.6') + implementation('io.vertx:vertx-pg-client:5.0.6') + implementation 'org.postgresql:postgresql:42.7.2' + implementation 'org.thymeleaf:thymeleaf:3.1.3.RELEASE' + implementation("org.freemarker:freemarker:2.3.33") +} + +tasks.withType(JavaCompile).configureEach { + sourceCompatibility = '21' + targetCompatibility = '21' + options.incremental(true) + options.compilerArgs << "-parameters" + options.encoding = "UTF-8" +} + +tasks.withType(JavaExec).configureEach { + jvmArgs += "-Dfile.encoding=utf-8" +} \ No newline at end of file diff --git a/frameworks/Java/tadx/build/libs/tadx-benchmark-0.0.1-SNAPSHOT.jar b/frameworks/Java/tadx/build/libs/tadx-benchmark-0.0.1-SNAPSHOT.jar new file mode 100644 index 00000000000..d54b8cfb1d9 Binary files /dev/null and b/frameworks/Java/tadx/build/libs/tadx-benchmark-0.0.1-SNAPSHOT.jar differ diff --git a/frameworks/Java/tadx/settings.gradle b/frameworks/Java/tadx/settings.gradle new file mode 100644 index 00000000000..530f00990bf --- /dev/null +++ b/frameworks/Java/tadx/settings.gradle @@ -0,0 +1,22 @@ +/** + * EN: Define the plugin download address + */ +pluginManagement { + repositories { + mavenLocal() + maven {url 'https://maven.aliyun.com/repository/public'} + maven {url 'https://maven.aliyun.com/repository/spring'} + maven {url 'https://maven.aliyun.com/repository/spring-plugin'} + mavenCentral() + } +} + +rootProject.name = 'tadx-benchmark' + +/** + * EN: Source code mode to reference Tad.x dependencies
+ * 1. Check out the Tad.x project source code to a directory
+ * 2. Reference the dev.gradle file in the project + */ +ext.TADX_FOLDER = '../../../../tadx.io/tadx' +apply from: ext.TADX_FOLDER+'/dev.gradle' \ No newline at end of file diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/Application.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/Application.java new file mode 100644 index 00000000000..eff70906918 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/Application.java @@ -0,0 +1,197 @@ +package io.tadx.benchmark; + +/*import io.netty.util.concurrent.MultithreadEventExecutorGroup; +import io.tadx.core.logging.LogFactory; +import io.vertx.core.*; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.*; +import io.vertx.core.impl.SysProps; +import io.vertx.core.internal.VertxInternal; +import io.vertx.core.json.JsonObject;*/ +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/*import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter;*/ + + +/** + * The main program loads the configuration and starts the server by `tadx-web`
+ * + * @author Tad.x team + * @since 1.0.0 + */ +@SpringBootApplication +public class Application { // extends VerticleBase implements Handler + + public static void main(String[] args) { + + SpringApplication.run(Application.class, args); + + + /*Vertx vertx = Vertx.vertx(new VertxOptions() + .setEventLoopPoolSize(Runtime.getRuntime().availableProcessors()) + .setPreferNativeTransport(true) + .setDisableTCCL(true) + ); + vertx.exceptionHandler(err -> { + LogFactory.frameworkLogger().warn("Uncaught exception: " + err); + }); + vertx.deployVerticle(Application.class.getName(), new DeploymentOptions().setInstances(Runtime.getRuntime().availableProcessors())) + .onComplete(event -> { + if (event.succeeded()) { + LogFactory.frameworkLogger().warn("Server listening on port " + 8080); + } else { + LogFactory.frameworkLogger().warn("Unable to start your application "+event.cause()); + } + });*/ + } + + /* + + private HttpServer server; + private CharSequence dateString; + private MultiMap plaintextHeaders; + private MultiMap jsonHeaders;private static final String PATH_PLAINTEXT = "/plaintext"; + private static final String PATH_JSON = "/json"; + private static final String PATH_DB = "/db"; + private static final String PATH_QUERIES = "/queries"; + private static final String PATH_UPDATES = "/updates"; + private static final String PATH_FORTUNES = "/fortunes"; + private static final String PATH_CACHING = "/cached-queries"; + + private static final CharSequence RESPONSE_TYPE_PLAIN = HttpHeaders.createOptimized("text/plain"); + private static final CharSequence RESPONSE_TYPE_HTML = HttpHeaders.createOptimized("text/html; charset=UTF-8"); + private static final CharSequence RESPONSE_TYPE_JSON = HttpHeaders.createOptimized("application/json"); + + private static final String HELLO_WORLD = "Hello, world!"; + private static final Buffer HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD, "UTF-8"); + + private static final CharSequence HEADER_SERVER = HttpHeaders.SERVER; + private static final CharSequence HEADER_DATE = HttpHeaders.DATE; + private static final CharSequence HEADER_CONTENT_TYPE = HttpHeaders.CONTENT_TYPE; + private static final CharSequence HEADER_CONTENT_LENGTH = HttpHeaders.CONTENT_LENGTH; + + private static final CharSequence HELLO_WORLD_LENGTH = HttpHeaders.createOptimized("" + HELLO_WORLD.length()); + private static final CharSequence JSON_LENGTH = HttpHeaders.createOptimized("" + JsonObject.of("message", "Hello, World!").toString().length()); + private static final CharSequence SERVER = HttpHeaders.createOptimized("vert.x"); + @Override + public Future start() throws Exception { + int port = 8000; + printConfig((VertxInternal) vertx); + server = vertx.createHttpServer(new HttpServerOptions() + .setHttp2ClearTextEnabled(false) + .setStrictThreadMode(true)) + .requestHandler(Application.this); + dateString = createDateHeader(); + plaintextHeaders = plaintextHeaders(); + jsonHeaders = jsonHeaders(); + JsonObject config = config(); + vertx.setPeriodic(1000, id -> { + dateString = createDateHeader(); + plaintextHeaders = plaintextHeaders(); + jsonHeaders = jsonHeaders(); + }); + return server.listen(port); + } + + @Override + public Future stop() throws Exception { + return super.stop(); + } + + @Override + public void handle(HttpServerRequest request) { + try { + switch (request.path()) { + case PATH_PLAINTEXT: + handlePlainText(request); + break; + case PATH_JSON: + handleJson(request); + break; + default: + request.response() + .setStatusCode(404) + .end(); + break; + } + } catch (Exception e) { + LogFactory.frameworkLogger().warn("Error: " + e); + request.response().setStatusCode(500).end(); + } + } + + private void handlePlainText(HttpServerRequest request) { + HttpServerResponse response = request.response(); + response.headers().setAll(plaintextHeaders); + response.end(HELLO_WORLD_BUFFER); + } + + private void handleJson(HttpServerRequest request) { + HttpServerResponse response = request.response(); + response.headers().setAll(jsonHeaders); + response.end(JsonObject.of("message", "Hello, World!").toString()); + } + + public static CharSequence createDateHeader() { + return HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); + } + + private MultiMap plaintextHeaders() { + return HttpHeaders + .headers() + .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_PLAIN) + .add(HEADER_SERVER, SERVER) + .add(HEADER_DATE, dateString) + .add(HEADER_CONTENT_LENGTH, HELLO_WORLD_LENGTH) + .copy(false); + } + + private MultiMap jsonHeaders() { + return HttpHeaders + .headers() + .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON) + .add(HEADER_SERVER, SERVER) + .add(HEADER_DATE, dateString) + .add(HEADER_CONTENT_LENGTH, JSON_LENGTH) + .copy(false); + } + + private static void printConfig(VertxInternal vertx) { + boolean nativeTransport = vertx.isNativeTransportEnabled(); + String transport = vertx.transport().getClass().getSimpleName(); + String version = "unknown"; + try { + InputStream in = Vertx.class.getClassLoader().getResourceAsStream("META-INF/vertx/vertx-version.txt"); + if (in == null) { + in = Vertx.class.getClassLoader().getResourceAsStream("vertx-version.txt"); + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[256]; + while (true) { + int amount = in.read(buffer); + if (amount == -1) { + break; + } + out.write(buffer, 0, amount); + } + version = out.toString(); + } catch (IOException e) { + LogFactory.frameworkLogger().warn("Could not read Vertx version" + e);; + } + LogFactory.frameworkLogger().warn("Vertx: " + version); + LogFactory.frameworkLogger().warn("Processors: " + Runtime.getRuntime().availableProcessors()); + LogFactory.frameworkLogger().warn("Event Loop Size: " + ((MultithreadEventExecutorGroup)vertx.nettyEventLoopGroup()).executorCount()); + LogFactory.frameworkLogger().warn("Native transport : " + nativeTransport); + LogFactory.frameworkLogger().warn("Transport : " + transport); + LogFactory.frameworkLogger().warn("Netty buffer bound check : " + System.getProperty("io.netty.buffer.checkBounds")); + LogFactory.frameworkLogger().warn("Netty buffer accessibility check : " + System.getProperty("io.netty.buffer.checkAccessible")); + for (SysProps sysProp : SysProps.values()) { + LogFactory.frameworkLogger().warn(sysProp.name + " : " + sysProp.get()); + } + }*/ +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/CachedQueries.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/CachedQueries.java new file mode 100644 index 00000000000..540545f8f43 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/CachedQueries.java @@ -0,0 +1,49 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.entity.World; +import io.tadx.data.DbStorage; +import io.tadx.web.HttpMethod; +import io.tadx.web.annotation.*; +import io.vertx.sqlclient.Tuple; + +import java.util.SplittableRandom; +import java.util.concurrent.ConcurrentHashMap; + +/** + * EN: The entry point of the application. + */ + +@RestController +public class CachedQueries { + + + private static final SplittableRandom RANDOM = new SplittableRandom(); + + private final static ConcurrentHashMap cache = new ConcurrentHashMap<>(); + + private final DbStorage dbStorage; + + public CachedQueries(DbStorage dbStorage) { + this.dbStorage = dbStorage; + } + + @RestFunction(mapping = "/cached_queries_rest", method = HttpMethod.GET) + public World[] execute(int count) { + if (count < 1) { + count = 1; + } else if (count > 500) { + count = 500; + } + World[] worlds = new World[count]; + for (int i = 0; i < count; i++) { + int id = randomWorld(); + worlds[i] = cache.computeIfAbsent(id, k -> dbStorage.findEntity(World.class, Tuple.of(id))); + } + return worlds; + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db1.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db1.java new file mode 100644 index 00000000000..2c15bd6a31e --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db1.java @@ -0,0 +1,47 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.DataMap; +import io.tadx.data.DbStorage; +import io.tadx.web.*; +import io.tadx.web.annotation.*; +import io.vertx.core.Future; +import io.vertx.core.Promise; +import io.vertx.sqlclient.Tuple; + +import java.util.SplittableRandom; + +/** + * EN: The entry point of the application. + */ + +@RestController(mapping = "/db_rest_druid") +public class Db1 { + + + private static final SplittableRandom RANDOM = new SplittableRandom(); + private final DbStorage dbStorage; + + public Db1(DbStorage dbStorage) { + this.dbStorage = dbStorage; + } + + //@RestFunction(method = HttpMethod.GET) + public Future execute() { + Promise promise = Promise.promise(); + World world = dbStorage.findEntity(World.class, Tuple.of(randomWorld())); + promise.complete(world); + return promise.future(); + } + + @RestFunction(method = HttpMethod.GET) + public DataMap executeSQL() { + return dbStorage.queryRow("SELECT id, randomnumber FROM world WHERE id = ?", Tuple.of(randomWorld())); + } + + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db2.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db2.java new file mode 100644 index 00000000000..78306a5b56d --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db2.java @@ -0,0 +1,51 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.web.HttpMethod; +import io.tadx.web.annotation.RestController; +import io.tadx.web.annotation.RestFunction; +import io.vertx.core.Future; +import io.vertx.core.Promise; +import io.vertx.sqlclient.*; + +import java.util.SplittableRandom; + +/** + * EN: The entry point of the application. + */ + +@RestController(mapping = "/db2") +public class Db2 { + private static final SplittableRandom RANDOM = new SplittableRandom(); + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + private final PreparedQuery> SELECT_WORLD_QUERY; + + public Db2() { + SqlClient client = PgConnPool.client(); + SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + } + + @RestFunction(method = HttpMethod.GET) + public Future execute() { + Promise promise = Promise.promise(); + SELECT_WORLD_QUERY.execute(Tuple.of(randomWorld())).onComplete(ar -> { + if (ar.succeeded()) { + Row row = ar.result().iterator().next(); + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + promise.complete(world); + } else { + promise.fail(ar.cause().getMessage()); + } + }); + return promise.future(); + } + + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db3.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db3.java new file mode 100644 index 00000000000..d05836687b5 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Db3.java @@ -0,0 +1,44 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.utils.AsyncUtils; +import io.tadx.web.HttpMethod; +import io.tadx.web.annotation.RestController; +import io.tadx.web.annotation.RestFunction; +import io.vertx.sqlclient.*; + +import java.util.SplittableRandom; + +/** + * EN: The entry point of the application. + */ + +@RestController(mapping = "/db3") +public class Db3 { + private static final SplittableRandom RANDOM = new SplittableRandom(); + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + private final PreparedQuery> SELECT_WORLD_QUERY; + + public Db3() { + + SqlClient client = PgConnPool.client(); + SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + } + + @RestFunction(method = HttpMethod.GET) + public World execute() { + RowSet rowSet = AsyncUtils.await(SELECT_WORLD_QUERY.execute(Tuple.of(randomWorld()))); + Row row = rowSet.iterator().next(); + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + return world; + } + + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Fortunes.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Fortunes.java new file mode 100644 index 00000000000..efc5910c91f --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Fortunes.java @@ -0,0 +1,38 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.entity.Fortune; +import io.tadx.data.DbStorage; +import io.tadx.web.annotation.*; +import io.tadx.web.*; +import io.tadx.web.template.FreemarkerEngine; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.SplittableRandom; + +/** + * EN: The entry point of the application. + */ + +@RestController +public class Fortunes { + + + private static final SplittableRandom RANDOM = new SplittableRandom(); + private final DbStorage dbStorage; + + public Fortunes(DbStorage dbStorage) { + this.dbStorage = dbStorage; + } + + @RestFunction(mapping = "/fortunes_2", method = HttpMethod.GET) + public WebResult execute() { + List fortunes = dbStorage.queryEntityList(Fortune.class); + fortunes.addFirst(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + return WebResult.pageResult(FreemarkerEngine.class, "/templates/Fortunes_freemarker.htm"); + //return WebResult.pageResult(DataMap.createNew().put("fortunes", fortunes), "/templates/Fortunes_thymeleaf.htm", TemplateType.THYMELEAF); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Queries.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Queries.java new file mode 100644 index 00000000000..cd53839d46a --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Queries.java @@ -0,0 +1,44 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.entity.World; +import io.tadx.data.DbStorage; +import io.tadx.web.HttpMethod; +import io.tadx.web.annotation.*; +import io.vertx.sqlclient.Tuple; + +import java.util.SplittableRandom; + +/** + * EN: The entry point of the application. + */ + +@RestController(mapping = "/queries_rest") +public class Queries { + + + private static final SplittableRandom RANDOM = new SplittableRandom(); + private final DbStorage dbStorage; + + public Queries(DbStorage dbStorage) { + this.dbStorage = dbStorage; + } + + @RestFunction(method = HttpMethod.GET) + public World[] execute(int queries) { + if (queries < 1) { + queries = 1; + } else if (queries > 500) { + queries = 500; + } + World[] worlds = new World[queries]; + for (int i = 0; i < queries; i++) { + worlds[i] = dbStorage.findEntity(World.class, Tuple.of(randomWorld())); + } + return worlds; + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Update.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Update.java new file mode 100644 index 00000000000..18b371b5b7d --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/controller/Update.java @@ -0,0 +1,49 @@ +package io.tadx.benchmark.controller; + +import io.tadx.benchmark.entity.World; +import io.tadx.data.DbStorage; +import io.tadx.web.HttpMethod; +import io.tadx.web.annotation.*; +import io.vertx.sqlclient.Tuple; + +import java.util.SplittableRandom; + +/** + * EN: The entry point of the application. + */ + +@RestController +public class Update { + + + private static final SplittableRandom RANDOM = new SplittableRandom(); + private final DbStorage dbStorage; + + public Update(DbStorage dbStorage) { + this.dbStorage = dbStorage; + } + + @RestFunction(mapping = "/update_rest", method = HttpMethod.GET) + public World[] execute(int queries) { + if (queries < 1) { + queries = 1; + } else if (queries > 500) { + queries = 500; + } + World[] worlds = new World[queries]; + //ArrayList updates = new ArrayList<>(); + for (int i = 0; i < queries; i++) { + worlds[i] = dbStorage.findEntity(World.class, Tuple.of(randomWorld())); + //updates.add(DataMap.createNew().put("id", worlds[i].id).put("randomnumber", randomWorld())); + dbStorage.execute("update world set randomnumber=? where id=?", Tuple.of(randomWorld(), worlds[i].id)); + } + //dbStorage.executeBatch("update world set randomnumber={randomnumber} where id={id}", updates); + + return worlds; + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } + +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/db/PgConnPool.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/db/PgConnPool.java new file mode 100644 index 00000000000..80f4d7172f0 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/db/PgConnPool.java @@ -0,0 +1,36 @@ +package io.tadx.benchmark.db; + +import io.tadx.core.TadxApplication; +import io.vertx.pgclient.PgBuilder; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.impl.SqlClientInternal; + +public class PgConnPool { + + private static SqlClientInternal client; + + public static SqlClientInternal client() { + if (client == null) { + createClient(); + } + return client; + } + + private static synchronized void createClient() { + if (client != null) { + return; + } + PgConnectOptions connectOptions = new PgConnectOptions(). + setPort(5432).setHost("tfb-database"). + setDatabase("hello_world"). + setUser("benchmarkdbuser"). + setPassword("benchmarkdbpass"). + setCachePreparedStatements(true). + setPreparedStatementCacheMaxSize(1024). + setPipeliningLimit(100000); + PoolOptions poolOptions = new PoolOptions().setMaxSize(1900); + // Create the client pool + client = (SqlClientInternal) PgBuilder.client().with(poolOptions).connectingTo(connectOptions).using(TadxApplication.vertx()).build(); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/entity/Fortune.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/entity/Fortune.java new file mode 100644 index 00000000000..c0155544557 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/entity/Fortune.java @@ -0,0 +1,32 @@ +package io.tadx.benchmark.entity; + +import io.tadx.core.data.EntityBase; +import io.tadx.core.data.annotation.Column; +import io.tadx.core.data.annotation.Entity; +import io.tadx.core.data.annotation.OutputField; +import io.tadx.core.data.annotation.PrimaryKey; + +@Entity(tableName = "fortune") +public class Fortune extends EntityBase implements Comparable { + + public Fortune() { + } + + public Fortune(int id, String message) { + this.id = id; + this.message = message; + } + + @PrimaryKey + @OutputField + public Integer id; + + @Column + @OutputField + public String message; + + @Override + public int compareTo(Fortune o) { + return message.compareTo(o.message); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/entity/World.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/entity/World.java new file mode 100644 index 00000000000..45d492f40c1 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/entity/World.java @@ -0,0 +1,19 @@ +package io.tadx.benchmark.entity; + +import io.tadx.core.data.EntityBase; +import io.tadx.core.data.annotation.Column; +import io.tadx.core.data.annotation.Entity; +import io.tadx.core.data.annotation.OutputField; +import io.tadx.core.data.annotation.PrimaryKey; + +@Entity(tableName = "world") +public class World extends EntityBase { + + @PrimaryKey + @OutputField + public Integer id; + + @Column + @OutputField + public Integer randomnumber; +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper1.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper1.java new file mode 100644 index 00000000000..f94cb31e03f --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper1.java @@ -0,0 +1,78 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.List; +import java.util.SplittableRandom; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * EN: Use ConcurrentHashMap to cache
+ * CN: 使用ConcurrentHashMap缓存 + */ +@RouteMapping(path = "/cached_queries1") +public class CachedQueriesMapper1 implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClientInternal client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD"; + + private final static ConcurrentHashMap cache = new ConcurrentHashMap<>(); + + public CachedQueriesMapper1() { + // Create the client pool + client = PgConnPool.client(); + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + + AtomicInteger key = new AtomicInteger(); + + client.preparedQuery(SELECT_WORLD).execute().onComplete(ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result().value(); + for (Row row : rows) { + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + cache.put(key.getAndIncrement(), world); + } + } + }); + } + + @Override + public void run(WebContext webContext) { + int count = webContext.request().readInt("count", 1); + if (count < 1) { + count = 1; + } else if (count > 500) { + count = 500; + } + + List worlds = new ArrayList<>(); + for (int i = 0; i < count; i++) { + int id = randomWorld(); + worlds.add(cache.get(id)); + } + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.stringify(worlds)); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(1000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper2.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper2.java new file mode 100644 index 00000000000..257eacd8136 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper2.java @@ -0,0 +1,79 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.SplittableRandom; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * EN: Use HashMap to cache
+ * CN: 使用HashMap缓存 + */ +@RouteMapping(path = "/cached_queries2") +public class CachedQueriesMapper2 implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClientInternal client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD"; + + private final static HashMap cache = new HashMap<>(); + + public CachedQueriesMapper2() { + + // Create the client pool + client = PgConnPool.client(); + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + + AtomicInteger key = new AtomicInteger(); + + client.preparedQuery(SELECT_WORLD).execute().onComplete(ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result().value(); + for (Row row : rows) { + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + cache.put(key.getAndIncrement(), world); + } + } + }); + } + + @Override + public void run(WebContext webContext) { + int count = webContext.request().readInt("count", 1); + if (count < 1) { + count = 1; + } else if (count > 500) { + count = 500; + } + + List worlds = new ArrayList<>(); + for (int i = 0; i < count; i++) { + int id = randomWorld(); + worlds.add(cache.get(id)); + } + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.stringify(worlds)); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(1000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper3.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper3.java new file mode 100644 index 00000000000..503a88922a4 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/CachedQueriesMapper3.java @@ -0,0 +1,80 @@ +package io.tadx.benchmark.route_mapper; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.List; +import java.util.SplittableRandom; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * EN: Use Caffeine to cache
+ * CN: 使用Caffeine缓存 + */ +@RouteMapping(path = "/cached_queries") +public class CachedQueriesMapper3 implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClientInternal client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD"; + + private final static Cache cache = Caffeine.newBuilder().maximumSize(10_000).build(); + + public CachedQueriesMapper3() { + // Create the client pool + client = PgConnPool.client(); + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + + AtomicInteger key = new AtomicInteger(); + + client.preparedQuery(SELECT_WORLD).execute().onComplete(ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result().value(); + for (Row row : rows) { + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + cache.put(key.getAndIncrement(), world); + } + } + }); + } + + @Override + public void run(WebContext webContext) { + int count = webContext.request().readInt("count", 1); + if (count < 1) { + count = 1; + } else if (count > 500) { + count = 500; + } + + ThreadLocalRandom current = ThreadLocalRandom.current(); + List worlds = new ArrayList<>(); + for (int i = 0; i < count; i++) { + worlds.add(cache.getIfPresent(current.nextInt(1000))); + } + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.stringify(worlds)); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(1000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_DbStorage.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_DbStorage.java new file mode 100644 index 00000000000..db382dcbcd7 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_DbStorage.java @@ -0,0 +1,45 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.core.data.DataMap; +import io.tadx.data.DbStorage; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Tuple; + +import java.util.SplittableRandom; + + +/** + * RouteMapper+DbStorage模式的/db测试 + * 备忘:实际性能与RestController不相上下(RouteMapper的) + */ +@RouteMapping(path = "/db_storage") +public class DbRouteMapper_DbStorage implements RouteMapper { + + + private static final SplittableRandom RANDOM = new SplittableRandom(); + private final DbStorage dbStorage; + + public DbRouteMapper_DbStorage(DbStorage dbStorage) { + this.dbStorage = dbStorage; + } + + @Override + public void run(WebContext webContext) { + //World world = dbStorage.findEntity(World.class, randomWorld()); + DataMap row = dbStorage.queryRow("SELECT id, randomnumber FROM world WHERE id = ?", Tuple.of(randomWorld())); + + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(row.toString()); + //.end(world.toJsonString()); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Jdbc.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Jdbc.java new file mode 100644 index 00000000000..49a200f4ca4 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Jdbc.java @@ -0,0 +1,60 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.core.TadxApplication; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.WebResult; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.jdbcclient.JDBCConnectOptions; +import io.vertx.jdbcclient.JDBCPool; +import io.vertx.sqlclient.*; + +import java.util.SplittableRandom; + + +/** + * RouteMapper+Jdbc Client 模式的/db测试 + */ +@RouteMapping(path = "/db_jdbc") +public class DbRouteMapper_Jdbc implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + JDBCConnectOptions connectOptions; + PoolOptions poolOptions; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=?"; + private final PreparedQuery> SELECT_WORLD_QUERY; + Pool pool; + + public DbRouteMapper_Jdbc() { + connectOptions = new JDBCConnectOptions() + .setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world") + .setUser("benchmarkdbuser") + .setPassword("benchmarkdbpass"); + // Pool options + poolOptions = new PoolOptions().setMaxSize(200); + // Create the client pool + pool = JDBCPool.pool(TadxApplication.vertx(), connectOptions, poolOptions); + SELECT_WORLD_QUERY = pool.preparedQuery(SELECT_WORLD); + } + + @Override + public void run(WebContext webContext) { + pool.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).onComplete(ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result(); + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(rows.iterator().next().toJson().toString()); + } else { + webContext.exception(WebResult.errorResult(ar.cause().getMessage())); + } + }); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Postgresql.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Postgresql.java new file mode 100644 index 00000000000..94c8ec4a960 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/DbRouteMapper_Postgresql.java @@ -0,0 +1,51 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.WebResult; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.*; + +import java.util.SplittableRandom; + + +/** + * RouteMapper+Postgresql Client 模式的/db测试 + */ +@RouteMapping(path = "/db") +public class DbRouteMapper_Postgresql implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClient client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + //private final PreparedQuery> SELECT_WORLD_QUERY; + + public DbRouteMapper_Postgresql() { + // Create the client pool + client = PgConnPool.client(); + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + } + + @Override + public void run(WebContext webContext) { + //client.preparedQuery(SELECT_WORLD)的性能高于SELECT_WORLD_QUERY.execute,但整体差异不大 + client.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).onComplete(ar -> { + if (ar.succeeded()) { + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(ar.result().iterator().next().toJson().toString()); + } else { + webContext.exception(WebResult.errorResult(ar.cause().getMessage())); + } + //client.close(); + }); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper1.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper1.java new file mode 100644 index 00000000000..ece8708932e --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper1.java @@ -0,0 +1,78 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.Fortune; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.WebResult; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.template.FreemarkerEngine; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +/** + * RouteMapper+Postgresql Client 模式的/queries测试(多查询时性能低于批量执行) + */ +@RouteMapping(path = "/fortunes") +public class FortunesRouteMapper1 implements RouteMapper { + + SqlClientInternal client; + private static final String SELECT_FORTUNES = "SELECT id, message FROM fortune"; + + public FortunesRouteMapper1() { + // Create the client pool + client = PgConnPool.client(); + } + + @Override + public void run(WebContext webContext) { + client.preparedQuery(SELECT_FORTUNES).execute(Tuple.tuple()).onComplete(ar -> { + if (ar.succeeded()) { + List fortunes = new ArrayList<>(); + + for (Row row : ar.result().value()) { + Fortune fortune = new Fortune(); + fortune.id = row.getInteger("id"); + fortune.message = row.getString("message"); + fortunes.add(fortune); + } + + fortunes.addFirst(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString); + webContext.complete(WebResult.pageResult(FreemarkerEngine.class).put("fortunes", fortunes).templateContent(""" + + + + Fortunes + + + + + + + + <#list fortunes as fortune> + + + + + +
idmessage
${fortune.id}${fortune.message?html}
+ + """)); + } + }); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper2.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper2.java new file mode 100644 index 00000000000..3694c27471e --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/FortunesRouteMapper2.java @@ -0,0 +1,61 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.Fortune; +import io.tadx.core.utils.Utils; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +/** + * RouteMapper+Postgresql Client 模式的/queries测试(多查询时性能低于批量执行) + */ +@RouteMapping(path = "/fortunes2") +public class FortunesRouteMapper2 implements RouteMapper { + SqlClientInternal client; + private static final String SELECT_FORTUNES = "SELECT id, message FROM fortune"; + + public FortunesRouteMapper2() { + // Create the client pool + client = PgConnPool.client();; + } + + @Override + public void run(WebContext webContext) { + client.preparedQuery(SELECT_FORTUNES).execute(Tuple.tuple()).onComplete(ar -> { + if (ar.succeeded()) { + List fortunes = new ArrayList<>(); + + for (Row row : ar.result().value()) { + Fortune fortune = new Fortune(); + fortune.id = row.getInteger("id"); + fortune.message = row.getString("message"); + fortunes.add(fortune); + } + + fortunes.addFirst(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + + StringBuilder sb = new StringBuilder("Fortunes"); + for (Fortune fortune : fortunes) { + sb.append(""); + } + sb.append("
idmessage
").append(fortune.id).append("").append(Utils.htmlEncode(fortune.message)).append("
"); + + webContext.routingContext().response() + .putHeader("Content-Type", "text/html;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString).end(sb.toString()); + } + }); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/JsonRouteMapper.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/JsonRouteMapper.java new file mode 100644 index 00000000000..a39cb03b980 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/JsonRouteMapper.java @@ -0,0 +1,24 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.*; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; + + +/** + * CN: 请求映射结果的接口 + */ +@RouteMapping(path = "/json") +public class JsonRouteMapper implements RouteMapper { + + @Override + public void run(WebContext webContext) { + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.createNew().put("message", "Hello, World!").stringify()); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/PlainTextRouteMapper.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/PlainTextRouteMapper.java new file mode 100644 index 00000000000..73e070c5dab --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/PlainTextRouteMapper.java @@ -0,0 +1,28 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.*; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.core.Future; +import io.vertx.ext.web.RoutingContext; + +import java.util.List; + + +/** + * CN: 请求映射结果的接口 + */ +@RouteMapping(path = "/plaintext") +public class PlainTextRouteMapper implements RouteMapper { + + @Override + public void run(WebContext webContext) { + webContext.routingContext().response() + .putHeader("Content-Type", "text/plain;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end("Hello, world!"); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper1_Postgresql.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper1_Postgresql.java new file mode 100644 index 00000000000..9452e138a76 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper1_Postgresql.java @@ -0,0 +1,75 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.*; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.List; +import java.util.SplittableRandom; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * RouteMapper+Postgresql Client 模式的/queries测试(多查询时性能低于批量执行) + */ +@RouteMapping(path = "/queries1") +public class QueriesRouteMapper1_Postgresql implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClientInternal client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + //private final PreparedQuery> SELECT_WORLD_QUERY; + + public QueriesRouteMapper1_Postgresql() { + // Create the client pool + client = PgConnPool.client(); + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + } + + @Override + public void run(WebContext webContext) { + int queries = webContext.request().readInt("queries", 1); + if (queries < 1) { + queries = 1; + } else if (queries > 500) { + queries = 500; + } + int count = queries; + + + + List worlds = new ArrayList<>(); + for (AtomicInteger i = new AtomicInteger(); i.get() < queries; i.getAndIncrement()) { + client.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).onComplete(ar -> { + if (ar.succeeded()) { + Row row = ar.result().iterator().next(); + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + worlds.add(world); + } else { + System.out.println("*******************: "+ar.cause()); + i.getAndDecrement(); + } + if (worlds.size() == count) { + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.stringify(worlds)); + } + }); + } + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper2_Postgresql.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper2_Postgresql.java new file mode 100644 index 00000000000..8e78dc92fc5 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/QueriesRouteMapper2_Postgresql.java @@ -0,0 +1,81 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.List; +import java.util.SplittableRandom; + + +/** + * RouteMapper+Postgresql Client 模式的/queries测试 + */ +@RouteMapping(path = "/queries") +public class QueriesRouteMapper2_Postgresql implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClientInternal client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + //private final PreparedQuery> SELECT_WORLD_QUERY; + + public QueriesRouteMapper2_Postgresql() { + + // Create the client pool + client = PgConnPool.client();; + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + } + + @Override + public void run(WebContext webContext) { + int queries = webContext.request().readInt("queries", 1); + if (queries < 1) { + queries = 1; + } else if (queries > 500) { + queries = 500; + } + + List batch = new ArrayList<>(); + int count = queries; + + for (int i = 0; i < queries; i++) { + batch.add(Tuple.of(randomWorld())); + } + client.preparedQuery(SELECT_WORLD) + .executeBatch(batch) + .onComplete(res -> { + if (res.succeeded()) { + // Process rows + RowSet rows = res.result(); + List worlds = new ArrayList<>(); + while (rows !=null) { + Row row = rows.iterator().next(); + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + worlds.add(world); + rows = rows.next(); + } + + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.stringify(worlds)); + } + }); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } +} diff --git a/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/UpdateMapper.java b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/UpdateMapper.java new file mode 100644 index 00000000000..334f61d7c98 --- /dev/null +++ b/frameworks/Java/tadx/src/main/java/io/tadx/benchmark/route_mapper/UpdateMapper.java @@ -0,0 +1,101 @@ +package io.tadx.benchmark.route_mapper; + +import io.tadx.benchmark.db.PgConnPool; +import io.tadx.benchmark.entity.World; +import io.tadx.core.data.Json; +import io.tadx.web.TadxWebApplication; +import io.tadx.web.WebContext; +import io.tadx.web.annotation.RouteMapping; +import io.tadx.web.route.RouteMapper; +import io.vertx.sqlclient.*; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.List; +import java.util.SplittableRandom; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * RouteMapper+Postgresql Client 模式的/queries测试(多查询时性能低于批量执行) + */ +@RouteMapping(path = "/update") +public class UpdateMapper implements RouteMapper { + + private static final SplittableRandom RANDOM = new SplittableRandom(); + SqlClientInternal client; + private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + //private final PreparedQuery> SELECT_WORLD_QUERY; + + public UpdateMapper() { + client = PgConnPool.client(); + //SELECT_WORLD_QUERY = client.preparedQuery(SELECT_WORLD); + } + + @Override + public void run(WebContext webContext) { + int queries = webContext.request().readInt("queries", 1); + if (queries < 1) { + queries = 1; + } else if (queries > 500) { + queries = 500; + } + int count = queries; + + + + List worlds = new ArrayList<>(); + for (AtomicInteger i = new AtomicInteger(); i.get() < queries; i.getAndIncrement()) { + client.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).onComplete(ar -> { + if (ar.succeeded()) { + Row row = ar.result().iterator().next(); + World world = new World(); + world.id = row.getInteger("id"); + world.randomnumber = row.getInteger("randomnumber"); + worlds.add(world); + } else { + System.out.println("*******************: "+ar.cause()); + i.getAndDecrement(); + } + if (worlds.size() == count) { + List params = new ArrayList<>(); + client.preparedQuery(buildUpdateQuery(worlds, params)).execute(Tuple.wrap(params)).onComplete(ar2 -> { + if (ar2.succeeded()) { + webContext.routingContext().response() + .putHeader("Content-Type", "application/json;charset=UTF-8") + .putHeader("Server", "Tad.x") + .putHeader("Date", TadxWebApplication.currentDateString) + .end(Json.stringify(worlds)); + } else { + webContext.response().end(ar2.cause().getMessage()); + } + }); + } + }); + } + } + + + private static String buildUpdateQuery(List worlds, List params) { + StringBuilder sql = new StringBuilder(); + sql.append("UPDATE world SET randomnumber = CASE ID"); + for (int i = 0; i < worlds.size(); i++) { + int offset = (i * 2) + 1; + sql.append(" WHEN $").append(offset).append(" THEN $").append(offset + 1); + params.add(worlds.get(i).id); + params.add(randomWorld()); + } + sql.append(" ELSE randomnumber"); + sql.append(" END WHERE ID IN ($1"); + for (int i = 1; i < worlds.size(); i++) { + int offset = (i * 2) + 1; + sql.append(",$").append(offset); + } + sql.append(")"); + return sql.toString(); + } + + static int randomWorld() { + return 1 + RANDOM.nextInt(10000); + } +} diff --git a/frameworks/Java/tadx/src/main/resources/application.yaml b/frameworks/Java/tadx/src/main/resources/application.yaml new file mode 100644 index 00000000000..af6ab59a47e --- /dev/null +++ b/frameworks/Java/tadx/src/main/resources/application.yaml @@ -0,0 +1,24 @@ + +tadx: + app-id: tadx-benchmark + app-title: Tad.x Framework Benchmark project + + logging: + level: warn + store-type: console + + web: + server: + port: 8080 + static-resource-list: + - prefix: /static + folder: /home/tadpole/dev/tadx.io/tadx-docs/docs/_static + + data: + db-storage: + type: postgresql + host: tfb-database + port: 5432 + database: hello_world + username: benchmarkdbuser + password: benchmarkdbpass diff --git a/frameworks/Java/tadx/src/main/resources/templates/Fortunes.htm b/frameworks/Java/tadx/src/main/resources/templates/Fortunes.htm new file mode 100644 index 00000000000..1c93fc01399 --- /dev/null +++ b/frameworks/Java/tadx/src/main/resources/templates/Fortunes.htm @@ -0,0 +1,18 @@ + + + + Fortunes + + + + + + + + + + + +
idmessage
1Sample Message
+ + \ No newline at end of file diff --git a/frameworks/Java/tadx/src/main/resources/templates/Fortunes_freemarker.htm b/frameworks/Java/tadx/src/main/resources/templates/Fortunes_freemarker.htm new file mode 100644 index 00000000000..3b8e74a2fa9 --- /dev/null +++ b/frameworks/Java/tadx/src/main/resources/templates/Fortunes_freemarker.htm @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + <#list fortunes as fortune> + + + + + +
idmessage
${fortune.id}${fortune.message?html}
+ + \ No newline at end of file diff --git a/frameworks/Java/tadx/src/main/resources/templates/Fortunes_thymeleaf.htm b/frameworks/Java/tadx/src/main/resources/templates/Fortunes_thymeleaf.htm new file mode 100644 index 00000000000..1c93fc01399 --- /dev/null +++ b/frameworks/Java/tadx/src/main/resources/templates/Fortunes_thymeleaf.htm @@ -0,0 +1,18 @@ + + + + Fortunes + + + + + + + + + + + +
idmessage
1Sample Message
+ + \ No newline at end of file diff --git a/frameworks/Java/tadx/tadx.dockerfile b/frameworks/Java/tadx/tadx.dockerfile new file mode 100644 index 00000000000..3ed655e444a --- /dev/null +++ b/frameworks/Java/tadx/tadx.dockerfile @@ -0,0 +1,41 @@ +#FROM gradle:8.14.3-jdk21 as build +#COPY --chown=gradle:gradle . /home/gradle/tadx-benchmark +#WORKDIR /home/gradle/tadx-benchmark +#RUN gradle build -x test --no-daemon + +#FROM gradle:8.14.3-jdk21 +# maven:3.9.9-eclipse-temurin-24-noble + +FROM maven:3.9.9-eclipse-temurin-24-noble +WORKDIR /tadx +#COPY --from=build /home/gradle/tadx-benchmark/build/libs/tadx-benchmark-0.0.1-SNAPSHOT.jar tadx.jar +COPY ./build/libs/tadx-benchmark-0.0.1-SNAPSHOT.jar tadx.jar + +EXPOSE 8080 + +CMD java $JAVA_OPTIONS \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -server -Xms2G \ + -XX:+UseParallelGC \ + -XX:+UseNUMA \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.flashPolicyHandler=false \ + -Dvertx.threadChecks=false \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableTCCL=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ + -Djdk.trackAllThreads=false \ + -Djava.lang.Integer.IntegerCache.high=10000 \ + -Dfile.encoding=UTF-8 \ + -jar tadx.jar diff --git a/frameworks/Java/tio-boot/pom.xml b/frameworks/Java/tio-boot/pom.xml index 021e8366683..3426dd7206a 100644 --- a/frameworks/Java/tio-boot/pom.xml +++ b/frameworks/Java/tio-boot/pom.xml @@ -8,12 +8,10 @@ ${project.artifactId} UTF-8 - 1.8 + 21 ${java.version} ${java.version} - 2.0.1 - - + 2.0.6 com.litongjava.tio.http.server.MainApp @@ -26,13 +24,14 @@ com.litongjava java-db - 1.5.3 + 1.5.6 + ch.qos.logback logback-classic - 1.2.13 + 1.3.12 @@ -45,7 +44,7 @@ com.alibaba.fastjson2 fastjson2 - 2.0.52 + 2.0.60 diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java index 5fb25eb411f..125b0b5a53d 100644 --- a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java @@ -1,11 +1,34 @@ package com.litongjava.tio.http.server; +import java.lang.Thread.Builder.OfVirtual; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + import com.litongjava.tio.boot.TioApplication; +import com.litongjava.tio.boot.server.TioBootServer; +import com.litongjava.tio.http.server.config.MainAppConfig; public class MainApp { public static void main(String[] args) { long start = System.currentTimeMillis(); + + // 1. 虚拟线程工厂(用于 work 线程) + OfVirtual ofVirtual = Thread.ofVirtual(); + ThreadFactory workTf = ofVirtual.name("t-io-v-", 1).factory(); + + // 2. 设置 readWorkers 使用的线程工厂 + TioBootServer server = TioBootServer.me(); + server.setWorkThreadFactory(workTf); + + // 3. 创建业务虚拟线程 Executor(每任务一个虚拟线程) + ThreadFactory bizTf = Thread.ofVirtual().name("t-biz-v-", 0).factory(); + + ExecutorService bizExecutor = Executors.newThreadPerTaskExecutor(bizTf); + + server.setBizExecutor(bizExecutor); + TioApplication.run(MainApp.class, new MainAppConfig(), args); long end = System.currentTimeMillis(); System.out.println((end - start) + "ms"); diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainAppConfig.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainAppConfig.java deleted file mode 100644 index eda7de88674..00000000000 --- a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainAppConfig.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.litongjava.tio.http.server; - -import com.litongjava.context.BootConfiguration; -import com.litongjava.tio.boot.server.TioBootServer; -import com.litongjava.tio.http.server.config.EhCachePluginConfig; -import com.litongjava.tio.http.server.config.EnjoyEngineConfig; -import com.litongjava.tio.http.server.config.MysqlDbConfig; -import com.litongjava.tio.http.server.handler.CacheHandler; -import com.litongjava.tio.http.server.handler.DbHandler; -import com.litongjava.tio.http.server.handler.IndexHandler; -import com.litongjava.tio.http.server.router.HttpRequestRouter; -import com.litongjava.tio.utils.environment.EnvUtils; - -public class MainAppConfig implements BootConfiguration { - - @Override - public void config() throws Exception { - - boolean db = EnvUtils.getBoolean("db", true); - if (db) { - try { - new MysqlDbConfig().init(); - } catch (Exception e) { - e.printStackTrace(); - } - } - // start enjoy and ehcache - try { - new EnjoyEngineConfig().engine(); - new EhCachePluginConfig().ehCachePlugin(); - } catch (Exception e) { - e.printStackTrace(); - } - - // add route - IndexHandler controller = new IndexHandler(); - - TioBootServer server = TioBootServer.me(); - HttpRequestRouter requestRouter = server.getRequestRouter(); - if (requestRouter != null) { - requestRouter.add("/plaintext", controller::plaintext); - requestRouter.add("/json", controller::json); - - DbHandler dbQueryController = new DbHandler(); - requestRouter.add("/db", dbQueryController::db); - requestRouter.add("/queries", dbQueryController::queries); - requestRouter.add("/updates", dbQueryController::updates); - requestRouter.add("/fortunes", dbQueryController::fortunes); - - CacheHandler cacheController = new CacheHandler(); - requestRouter.add("/cachedQuery", cacheController::cachedQuery); - } - } -} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MainAppConfig.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MainAppConfig.java new file mode 100644 index 00000000000..4d1bdf118b3 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MainAppConfig.java @@ -0,0 +1,53 @@ +package com.litongjava.tio.http.server.config; + +import com.litongjava.context.BootConfiguration; +import com.litongjava.tio.boot.server.TioBootServer; +import com.litongjava.tio.http.server.handler.CacheHandler; +import com.litongjava.tio.http.server.handler.DbHandler; +import com.litongjava.tio.http.server.handler.JsonHandler; +import com.litongjava.tio.http.server.handler.PlaintextHandler; +import com.litongjava.tio.http.server.router.HttpRequestRouter; +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MainAppConfig implements BootConfiguration { + + @Override + public void config() throws Exception { + + boolean db = EnvUtils.getBoolean("db", true); + if (db) { + try { + new MysqlDbConfig().init(); + } catch (Exception e) { + e.printStackTrace(); + } + } + // start enjoy and ehcache + try { + new EnjoyEngineConfig().engine(); + new EhCachePluginConfig().ehCachePlugin(); + } catch (Exception e) { + e.printStackTrace(); + } + + // add route + JsonHandler jsonHanlder = new JsonHandler(); + + PlaintextHandler plaintextHandler = new PlaintextHandler(); + TioBootServer server = TioBootServer.me(); + HttpRequestRouter requestRouter = server.getRequestRouter(); + if (requestRouter != null) { + requestRouter.add("/plaintext", plaintextHandler); + requestRouter.add("/json", jsonHanlder); + + DbHandler dbQueryController = new DbHandler(); + requestRouter.add("/db", dbQueryController::db); + requestRouter.add("/queries", dbQueryController::queries); + requestRouter.add("/updates", dbQueryController::updates); + requestRouter.add("/fortunes", dbQueryController::fortunes); + + CacheHandler cacheController = new CacheHandler(); + requestRouter.add("/cachedQuery", cacheController); + } + } +} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java index ad11cc294ea..ab2188040b4 100644 --- a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java @@ -14,11 +14,12 @@ import com.litongjava.tio.http.common.HttpResponse; import com.litongjava.tio.http.server.utils.RandomUtils; -public class CacheHandler { +public class CacheHandler implements HttpRequestHandler { // private Logger log = LoggerFactory.getLogger(this.getClass()); String sql = "SELECT id, randomNumber FROM world WHERE id = ?"; - public HttpResponse cachedQuery(HttpRequest request) { + @Override + public HttpResponse handle(HttpRequest request) throws Exception { String queries = request.getParam("queries"); int queryCount = RandomUtils.parseQueryCount(queries); @@ -38,4 +39,4 @@ public HttpResponse cachedQuery(HttpRequest request) { response.setBody(JSON.toJSONBytes(recordMaps)); return response; } -} +} \ No newline at end of file diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java deleted file mode 100644 index 2122b1608e9..00000000000 --- a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.litongjava.tio.http.server.handler; - -import java.nio.charset.StandardCharsets; - -import com.alibaba.fastjson2.JSON; -import com.litongjava.tio.boot.http.TioRequestContext; -import com.litongjava.tio.http.common.HttpRequest; -import com.litongjava.tio.http.common.HttpResponse; -import com.litongjava.tio.http.common.utils.MimeTypeUtils; -import com.litongjava.tio.http.server.model.Message; - -/** - * ab -k -n1000000 -c10 http://127.0.0.1:8080/json ab -k -n1000000 -c10 - * http://127.0.0.1:8080/plaintext - */ -public class IndexHandler { - - private static final String HELLO_WORLD = "Hello, World!"; - - private static final byte[] HELLO_WORLD_BYTES = HELLO_WORLD.getBytes(StandardCharsets.UTF_8); - private static final byte[] JSON_BYTES = JSON.toJSONBytes(new Message(HELLO_WORLD)); - - public HttpResponse plaintext(HttpRequest request) { - HttpResponse response = TioRequestContext.getResponse(); - response.setBody(HELLO_WORLD_BYTES); - String mimeTypeStr = MimeTypeUtils.getTextUTF8(); - response.setContentType(mimeTypeStr); - return response; - } - - public HttpResponse json(HttpRequest request) { - HttpResponse response = TioRequestContext.getResponse(); - response.setBody(JSON_BYTES); - String mimeTypeStr = MimeTypeUtils.getJsonUTF8(); - response.setContentType(mimeTypeStr); - return response; - } -} \ No newline at end of file diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/JsonHandler.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/JsonHandler.java new file mode 100644 index 00000000000..90e3e6ec5b4 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/JsonHandler.java @@ -0,0 +1,27 @@ +package com.litongjava.tio.http.server.handler; + +import com.alibaba.fastjson2.JSON; +import com.litongjava.tio.boot.http.TioRequestContext; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.common.utils.MimeTypeUtils; +import com.litongjava.tio.http.server.model.Message; + +/** + * ab -k -n1000000 -c10 http://127.0.0.1:8080/json ab -k -n1000000 -c10 + * http://127.0.0.1:8080/plaintext + */ +public class JsonHandler implements HttpRequestHandler { + + private static final String HELLO_WORLD = "Hello, World!"; + private static final byte[] JSON_BYTES = JSON.toJSONBytes(new Message(HELLO_WORLD)); + + @Override + public HttpResponse handle(HttpRequest httpRequest) throws Exception { + HttpResponse response = TioRequestContext.getResponse(); + response.setBody(JSON_BYTES); + String mimeTypeStr = MimeTypeUtils.getJsonUTF8(); + response.setContentType(mimeTypeStr); + return response; + } +} \ No newline at end of file diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/PlaintextHandler.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/PlaintextHandler.java new file mode 100644 index 00000000000..3e2f366eb7b --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/PlaintextHandler.java @@ -0,0 +1,25 @@ +package com.litongjava.tio.http.server.handler; + +import java.nio.charset.StandardCharsets; + +import com.litongjava.tio.boot.http.TioRequestContext; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.common.utils.MimeTypeUtils; + +public class PlaintextHandler implements HttpRequestHandler { + + private static final String HELLO_WORLD = "Hello, World!"; + + private static final byte[] HELLO_WORLD_BYTES = HELLO_WORLD.getBytes(StandardCharsets.UTF_8); + + @Override + public HttpResponse handle(HttpRequest httpRequest) throws Exception { + HttpResponse response = TioRequestContext.getResponse(); + response.setBody(HELLO_WORLD_BYTES); + String mimeTypeStr = MimeTypeUtils.getTextUTF8(); + response.setContentType(mimeTypeStr); + return response; + } + +} diff --git a/frameworks/Java/tio-boot/src/main/resources/app.properties b/frameworks/Java/tio-boot/src/main/resources/app.properties index 1c202a1c753..8c93d263ae9 100644 --- a/frameworks/Java/tio-boot/src/main/resources/app.properties +++ b/frameworks/Java/tio-boot/src/main/resources/app.properties @@ -1,5 +1,6 @@ http.response.header.showServer=true server.port=8080 +server.protocol=http #JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false&allowPublicKeyRetrieval=true #JDBC_USER=root #JDBC_PSWD=robot_123456# diff --git a/frameworks/Java/tio-boot/tio-boot.dockerfile b/frameworks/Java/tio-boot/tio-boot.dockerfile index 3b779333565..459a811e063 100644 --- a/frameworks/Java/tio-boot/tio-boot.dockerfile +++ b/frameworks/Java/tio-boot/tio-boot.dockerfile @@ -1,4 +1,4 @@ -FROM litongjava/maven:3.8.8-jdk8u391 AS builder +FROM litongjava/maven:3.8.8-jdk_21_0_6 AS builder WORKDIR /app COPY pom.xml pom.xml @@ -8,7 +8,7 @@ COPY src src RUN mvn package -Passembly -q RUN ls -l && ls -l target -FROM litongjava/jre:8u391-stable-slim +FROM litongjava/jdk:21_0_6-stable-slim WORKDIR /app diff --git a/frameworks/Java/today/.gitignore b/frameworks/Java/today/.gitignore index ed040c778b1..5f82467bf0d 100644 --- a/frameworks/Java/today/.gitignore +++ b/frameworks/Java/today/.gitignore @@ -7,4 +7,5 @@ build .idea today.properties gradle -gradlew \ No newline at end of file +gradlew +gradlew.bat \ No newline at end of file diff --git a/frameworks/Java/today/benchmark_config.json b/frameworks/Java/today/benchmark_config.json index c44a0306ce5..7b5caa570ba 100755 --- a/frameworks/Java/today/benchmark_config.json +++ b/frameworks/Java/today/benchmark_config.json @@ -1,5 +1,8 @@ { "framework": "today", + "maintainers": [ + "TAKETODAY" + ], "tests": [ { "default": { @@ -24,7 +27,8 @@ "database_os": "Linux", "display_name": "TODAY", "notes": "", - "versus": "None" + "versus": "None", + "tags": [] } } ] diff --git a/frameworks/Java/today/build.gradle b/frameworks/Java/today/build.gradle index 0925eff2b4a..157a6101501 100644 --- a/frameworks/Java/today/build.gradle +++ b/frameworks/Java/today/build.gradle @@ -10,21 +10,22 @@ configure(allprojects) { repositories { mavenLocal() mavenCentral() - maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } + maven { url = "https://central.sonatype.com/repository/maven-snapshots/" } } } dependencies { - implementation 'cn.taketoday:today-starter-netty' - implementation 'cn.taketoday:today-starter-json' - implementation 'cn.taketoday:today-starter-jdbc' - implementation 'cn.taketoday:today-starter-web' - implementation 'cn.taketoday:today-starter-freemarker' + implementation 'cn.taketoday:infra-starter-application' + implementation 'cn.taketoday:infra-starter-netty-server' + implementation 'cn.taketoday:infra-starter-json' + implementation 'cn.taketoday:infra-starter-jdbc' + implementation 'cn.taketoday:infra-starter-persistence' + implementation 'cn.taketoday:infra-starter-webmvc' + implementation 'cn.taketoday:infra-starter-freemarker' - implementation 'mysql:mysql-connector-java' + implementation 'com.mysql:mysql-connector-j' implementation 'ch.qos.logback:logback-classic' - implementation 'com.github.ben-manes.caffeine:caffeine' implementation('io.netty:netty-transport-native-epoll') { artifact { @@ -32,23 +33,35 @@ dependencies { } } - implementation('io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.21.Final') { + implementation("io.netty:netty-transport-native-epoll") { artifact { - classifier = 'linux-x86_64' + classifier = 'linux-aarch_64' } } -// implementation('io.netty:netty-transport-native-kqueue') { -// artifact { -// classifier = 'osx-aarch_64' -// } -// } + implementation("io.netty:netty-transport-native-kqueue") { + artifact { + classifier = 'osx-aarch_64' + } + } + + implementation('io.netty:netty-transport-native-io_uring') { + artifact { + classifier = 'linux-aarch_64' + } + } + + implementation('io.netty:netty-transport-native-io_uring') { + artifact { + classifier = 'linux-x86_64' + } + } } java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } application { @@ -65,6 +78,7 @@ application { "-Dio.netty.leakDetection.level=disabled", "-Dio.netty.iouring.iosqeAsyncThreshold=32000", "-Djava.lang.Integer.IntegerCache.high=10000", + "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/java.nio=ALL-UNNAMED", "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" ] diff --git a/frameworks/Java/today/gradle.properties b/frameworks/Java/today/gradle.properties index 088db4d0de3..1accca05774 100644 --- a/frameworks/Java/today/gradle.properties +++ b/frameworks/Java/today/gradle.properties @@ -1,6 +1,5 @@ version=1.1.0 -#infraVersion=5.0-Draft.2 -infraVersion=5.0-Draft.2-SNAPSHOT +infraVersion=5.0-Draft.6-SNAPSHOT org.gradle.caching=true org.gradle.jvmargs=-Xmx2048m diff --git a/frameworks/Java/today/settings.gradle b/frameworks/Java/today/settings.gradle index 8cb2bee3734..5210810432c 100644 --- a/frameworks/Java/today/settings.gradle +++ b/frameworks/Java/today/settings.gradle @@ -1,9 +1,7 @@ buildscript { repositories { mavenLocal() - maven { - url "https://oss.sonatype.org/content/repositories/snapshots/" - } + maven { url = "https://central.sonatype.com/repository/maven-snapshots/" } mavenCentral() } diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java index b5496ce042d..99a9c2811d8 100644 --- a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java @@ -2,26 +2,24 @@ import java.time.ZonedDateTime; -import javax.sql.DataSource; - import infra.beans.factory.annotation.DisableAllDependencyInjection; import infra.beans.factory.config.BeanDefinition; import infra.context.annotation.Configuration; import infra.context.annotation.Role; -import infra.jdbc.RepositoryManager; -import infra.persistence.EntityManager; import infra.stereotype.Component; import infra.web.server.WebServerFactoryCustomizer; -import infra.web.server.error.SendErrorHandler; -import infra.web.server.support.NettyRequestConfig; -import infra.web.server.support.NettyWebServerFactory; +import infra.web.server.netty.NettyWebServerFactory; +import infra.web.server.netty.config.NettyRequestConfigCustomizer; +import io.netty.channel.IoHandlerFactory; +import io.netty.channel.MultiThreadIoEventLoopGroup; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.uring.IoUring; +import io.netty.channel.uring.IoUringIoHandler; +import io.netty.channel.uring.IoUringServerSocketChannel; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpHeadersFactory; -import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; -import io.netty.incubator.channel.uring.IOUring; -import io.netty.incubator.channel.uring.IOUringEventLoopGroup; -import io.netty.incubator.channel.uring.IOUringServerSocketChannel; +import io.netty.util.concurrent.DefaultThreadFactory; import static infra.http.HttpHeaders.DATE_FORMATTER; @@ -34,52 +32,46 @@ @Configuration(proxyBeanMethods = false) class AppConfig { - @Component - public static RepositoryManager repositoryManager(DataSource dataSource) { - return new RepositoryManager(dataSource); - } - - @Component - public static EntityManager entityManager(RepositoryManager repositoryManager) { - return repositoryManager.getEntityManager(); - } - @Component public static WebServerFactoryCustomizer factoryWebServerFactoryCustomizer() { return factory -> { - if (IOUring.isAvailable()) { - IOUringEventLoopGroup loopGroup = new IOUringEventLoopGroup(); - factory.setAcceptorGroup(loopGroup); - factory.setWorkerGroup(loopGroup); - factory.setSocketChannel(IOUringServerSocketChannel.class); + if (IoUring.isAvailable()) { + factory.setSocketChannel(IoUringServerSocketChannel.class); + + IoHandlerFactory ioHandlerFactory = IoUringIoHandler.newFactory(); + if (factory.getAcceptorGroup() == null) { + factory.setAcceptorGroup(new MultiThreadIoEventLoopGroup(factory.getAcceptorThreadCount(), + new DefaultThreadFactory("uring-acceptor"), ioHandlerFactory)); + } + if (factory.getWorkerGroup() == null) { + factory.setWorkerGroup(new MultiThreadIoEventLoopGroup( + factory.getWorkThreadCount(), new DefaultThreadFactory("uring-workers"), ioHandlerFactory)); + } } + + System.out.println("IoUring: " + IoUring.isAvailable()); + System.out.println("Epoll: " + Epoll.isAvailable()); }; } @Component @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - public static NettyRequestConfig nettyRequestConfig(SendErrorHandler sendErrorHandler) { - var factory = new DefaultHttpDataFactory(false); - - return NettyRequestConfig.forBuilder(false) - .httpDataFactory(factory) - .sendErrorHandler(sendErrorHandler) - .headersFactory(new HttpHeadersFactory() { - - @Override - public HttpHeaders newHeaders() { - HttpHeaders headers = new ResponseHeaders(); - headers.set("Server", "TODAY"); - headers.set("Date", DATE_FORMATTER.format(ZonedDateTime.now())); - return headers; - } + static NettyRequestConfigCustomizer nettyRequestConfigCustomizer() { + return builder -> builder.headersFactory(new HttpHeadersFactory() { + + @Override + public HttpHeaders newHeaders() { + HttpHeaders headers = new ResponseHeaders(); + headers.set("Server", "TODAY"); + headers.set("Date", DATE_FORMATTER.format(ZonedDateTime.now())); + return headers; + } - @Override - public HttpHeaders newEmptyHeaders() { - return new ResponseHeaders(); - } - }) - .build(); + @Override + public HttpHeaders newEmptyHeaders() { + return new ResponseHeaders(); + } + }); } static class ResponseHeaders extends DefaultHttpHeaders { diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java index 3000a073aab..a63bc9ce01d 100644 --- a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java @@ -1,6 +1,7 @@ package cn.taketoday.benchmark.http; -import java.util.Comparator; +import org.jspecify.annotations.Nullable; + import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; @@ -10,7 +11,6 @@ import cn.taketoday.benchmark.model.World; import infra.http.MediaType; import infra.http.ResponseEntity; -import infra.lang.Nullable; import infra.persistence.EntityManager; import infra.ui.Model; import infra.util.concurrent.Future; @@ -50,9 +50,8 @@ public String plaintext() { return "Hello, World!"; } - @Nullable @GET("/db") - public World db() { + public @Nullable World db() { return entityManager.findById(World.class, nextInt()); } @@ -70,31 +69,36 @@ public List cachedQueries(@Nullable String count) { @GET("/updates") public Future> updates(@Nullable String queries) { return Future.combine(randomNumbers() - .limit(parseQueryCount(queries)) - .mapToObj(this::findWorldByIdFuture) - .map(worldFuture -> worldFuture.map(world -> { - world.setRandomNumber(nextInt()); - entityManager.updateById(world); - return world; - }))).asList(); + .limit(parseQueryCount(queries)) + .mapToObj(this::findWorldByIdFuture) + .map(worldFuture -> worldFuture.map(world -> { + if (world != null) { + world.setRandomNumber(nextInt()); + entityManager.updateById(world); + return world; + } + return null; + })) + ) + .acceptFailure() + .asList(); } @GET("/fortunes") public ViewRef fortunes(Model model) { List fortunes = entityManager.find(Fortune.class); fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - fortunes.sort(Comparator.comparing(Fortune::getMessage)); + fortunes.sort(null); model.addAttribute("fortunes", fortunes); return ViewRef.forViewName("fortunes"); } - private Future findWorldByIdFuture(int id) { + private Future<@Nullable World> findWorldByIdFuture(int id) { return Future.run(() -> findWorldById(id)); } - @Nullable - private World findWorldById(int id) { + private @Nullable World findWorldById(int id) { return entityManager.findById(World.class, id); } diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/package-info.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/package-info.java index 4ef5fb0311b..7ec106562b3 100644 --- a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/package-info.java +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/package-info.java @@ -1,6 +1,4 @@ -@NonNullApi -@NonNullFields +@NullMarked package cn.taketoday.benchmark.http; -import infra.lang.NonNullApi; -import infra.lang.NonNullFields; \ No newline at end of file +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java index 1df119d4a3d..8cd2269f2d4 100644 --- a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java @@ -6,7 +6,7 @@ import infra.persistence.Table; @Table("fortune") -public class Fortune { +public class Fortune implements Comparable { @Id private Integer id; @@ -52,4 +52,9 @@ public int hashCode() { return Objects.hash(id, message); } + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); + } + } diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/package-info.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/package-info.java index 115f7640198..2fe732f0e95 100644 --- a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/package-info.java +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/package-info.java @@ -1,6 +1,4 @@ -@NonNullApi -@NonNullFields +@NullMarked package cn.taketoday.benchmark.model; -import infra.lang.NonNullApi; -import infra.lang.NonNullFields; \ No newline at end of file +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/package-info.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/package-info.java index 518576b46e9..aba1fd4f4bc 100644 --- a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/package-info.java +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/package-info.java @@ -1,6 +1,4 @@ -@NonNullApi -@NonNullFields +@NullMarked package cn.taketoday.benchmark; -import infra.lang.NonNullApi; -import infra.lang.NonNullFields; \ No newline at end of file +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/application-test.yaml b/frameworks/Java/today/src/main/resources/application-test.yaml index 7d554af1c14..388ce94a2a0 100644 --- a/frameworks/Java/today/src/main/resources/application-test.yaml +++ b/frameworks/Java/today/src/main/resources/application-test.yaml @@ -11,5 +11,6 @@ server: netty: acceptor-threads: 8 worker-threads: 16 - max-connection: 8192 - validate-headers: false \ No newline at end of file + max-connection: 10240000 + validate-headers: false + diff --git a/frameworks/Java/today/src/main/resources/application.yaml b/frameworks/Java/today/src/main/resources/application.yaml index aba9b42e36a..d121f913361 100644 --- a/frameworks/Java/today/src/main/resources/application.yaml +++ b/frameworks/Java/today/src/main/resources/application.yaml @@ -3,6 +3,11 @@ app: server: port: 8080 + http2: + enabled: false + use-virtual-thread-service-executor: true + netty: + auto-read: ${server.http2.enabled} infra: output: @@ -31,7 +36,6 @@ datasource: driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 256 - connection-test-query: 'select 1' logging: level: diff --git a/frameworks/Java/today/today.dockerfile b/frameworks/Java/today/today.dockerfile index 643bbe4c00a..835856d73a9 100644 --- a/frameworks/Java/today/today.dockerfile +++ b/frameworks/Java/today/today.dockerfile @@ -1,10 +1,9 @@ -FROM gradle:8.13.0-jdk21 as build +FROM gradle:9.3.1-jdk25 as build COPY --chown=gradle:gradle . /infra-src WORKDIR /infra-src RUN gradle installDist --no-daemon -#FROM openjdk:21 -FROM bellsoft/liberica-openjre-debian:21.0.5 +FROM bellsoft/liberica-openjre-debian:25.0.2 RUN apt install findutils WORKDIR /today COPY --from=build /infra-src/build/install/today/ ./ diff --git a/frameworks/Java/undertow-jersey/pom.xml b/frameworks/Java/undertow-jersey/pom.xml index 84bdc08753d..304d384f7a4 100644 --- a/frameworks/Java/undertow-jersey/pom.xml +++ b/frameworks/Java/undertow-jersey/pom.xml @@ -174,7 +174,7 @@ io.undertow undertow-core - 2.3.20.Final + 2.3.21.Final diff --git a/frameworks/Java/undertow/benchmark_config.json b/frameworks/Java/undertow/benchmark_config.json index 27c2a991a9a..f47ee1dbe70 100644 --- a/frameworks/Java/undertow/benchmark_config.json +++ b/frameworks/Java/undertow/benchmark_config.json @@ -18,7 +18,8 @@ "database_os": "Linux", "display_name": "undertow", "notes": "", - "versus": "" + "versus": "", + "tags": ["broken"] }, "postgresql" : { "db_url": "/db", @@ -39,7 +40,8 @@ "database_os": "Linux", "display_name": "undertow-postgresql", "notes": "", - "versus": "" + "versus": "", + "tags": ["broken"] } }] } diff --git a/frameworks/Java/undertow/pom.xml b/frameworks/Java/undertow/pom.xml index b75308fdd5c..7b75e4d8552 100644 --- a/frameworks/Java/undertow/pom.xml +++ b/frameworks/Java/undertow/pom.xml @@ -20,7 +20,7 @@ 3.2.2 0.9.10 42.7.2 - 2.3.20.Final + 2.3.21.Final diff --git a/frameworks/Java/vertx-web/pom.xml b/frameworks/Java/vertx-web/pom.xml index df831155363..333edfb3829 100644 --- a/frameworks/Java/vertx-web/pom.xml +++ b/frameworks/Java/vertx-web/pom.xml @@ -7,12 +7,12 @@ io.vertx vertx-web-benchmark - 4.3.8 + 5.0.5 UTF-8 - 17 - 17 + 25 + 25 io.vertx.benchmark.App @@ -35,10 +35,15 @@ vertx-core + + io.vertx + vertx-launcher-application + + com.fasterxml.jackson.module jackson-module-blackbird - 2.14.2 + 2.19.0 @@ -56,11 +61,19 @@ vertx-web-templ-rocker + + + + io.netty + netty-transport-native-io_uring + linux-x86_64 + @@ -70,7 +83,7 @@ com.fizzed rocker-maven-plugin - 1.3.0 + 2.4.0 generate-rocker-templates @@ -81,7 +94,7 @@ ${project.basedir}/src/main/resources true - 17 + 25 @@ -94,7 +107,7 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.1 + 3.6.1 package @@ -105,7 +118,7 @@ - io.vertx.core.Launcher + io.vertx.launcher.application.VertxApplication ${main.verticle} diff --git a/frameworks/Java/vertx-web/src/main/java/io/vertx/benchmark/App.java b/frameworks/Java/vertx-web/src/main/java/io/vertx/benchmark/App.java index 5630df8d2f2..2601ce215d4 100644 --- a/frameworks/Java/vertx-web/src/main/java/io/vertx/benchmark/App.java +++ b/frameworks/Java/vertx-web/src/main/java/io/vertx/benchmark/App.java @@ -26,7 +26,6 @@ public class App extends AbstractVerticle { static { DatabindCodec.mapper().registerModule(new BlackbirdModule()); - DatabindCodec.prettyMapper().registerModule(new BlackbirdModule()); } // TODO: this function can be moved into `PgClientBenchmark`, made static, and renamed when static declarations in inner classes are supported (when the JDK is upgraded to 16 or above). @@ -50,9 +49,9 @@ private void createPgClientBenchmarkAsync(Vertx vertx, JsonObject config, Handle */ private final class PgClientBenchmark { - private static final String UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2"; - private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; - private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE"; + private static final String UPDATE_WORLD = "UPDATE world SET randomnumber = $1 WHERE id = $2"; + private static final String SELECT_WORLD = "SELECT id, randomnumber FROM world WHERE id = $1"; + private static final String SELECT_FORTUNE = "SELECT id, message FROM fortune"; private final PgConnection client; @@ -67,7 +66,7 @@ private PgClientBenchmark(PgConnection client, RockerTemplateEngine engine) { public void dbHandler(final RoutingContext ctx) { client .preparedQuery(SELECT_WORLD) - .execute(Tuple.of(randomWorld()), res -> { + .execute(Tuple.of(randomWorld())).andThen(res -> { if (res.succeeded()) { final RowIterator resultSet = res.result().iterator(); if (!resultSet.hasNext()) { @@ -97,7 +96,7 @@ public void queriesHandler(final RoutingContext ctx) { final int[] cnt = { 0 }; for (int i = 0; i < queries; i++) { - client.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld()), res -> { + client.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).andThen(res -> { if (!failed[0]) { if (res.failed()) { failed[0] = true; @@ -124,7 +123,7 @@ public void queriesHandler(final RoutingContext ctx) { public void fortunesHandler(final RoutingContext ctx) { - client.preparedQuery(SELECT_FORTUNE).execute(ar -> { + client.preparedQuery(SELECT_FORTUNE).execute().andThen(ar -> { if (ar.succeeded()) { final RowIterator resultSet = ar.result().iterator(); if (!resultSet.hasNext()) { @@ -145,7 +144,7 @@ public void fortunesHandler(final RoutingContext ctx) { ctx.put("fortunes", fortunes); // and now delegate to the engine to render it. - engine.render(ctx.data(), "templates/Fortunes.rocker.html", res -> { + engine.render(ctx.data(), "templates/Fortunes.rocker.html").andThen(res -> { if (res.succeeded()) { ctx.response() .putHeader(HttpHeaders.SERVER, SERVER) @@ -171,7 +170,7 @@ public void updateHandler(final RoutingContext ctx) { for (int i = 0; i < worlds.length; i++) { int id = randomWorld(); - client.preparedQuery(SELECT_WORLD).execute(Tuple.of(id), ar2 -> { + client.preparedQuery(SELECT_WORLD).execute(Tuple.of(id)).andThen(ar2 -> { if (!failed[0]) { if (ar2.failed()) { failed[0] = true; @@ -190,7 +189,7 @@ public void updateHandler(final RoutingContext ctx) { batch.add(Tuple.of(world.getRandomNumber(), world.getId())); } - client.preparedQuery(UPDATE_WORLD).executeBatch(batch, ar3 -> { + client.preparedQuery(UPDATE_WORLD).executeBatch(batch).andThen(ar3 -> { if (ar3.failed()) { ctx.fail(ar3.cause()); return; @@ -273,7 +272,7 @@ public void start(Promise startPromise) { .end("Hello, World!"); }); - vertx.createHttpServer().requestHandler(app).listen(8080, listen -> { + vertx.createHttpServer().requestHandler(app).listen(8080).andThen(listen -> { if (listen.failed()) { listen.cause().printStackTrace(); System.exit(1); diff --git a/frameworks/Java/vertx-web/vertx-web-postgres.dockerfile b/frameworks/Java/vertx-web/vertx-web-postgres.dockerfile index a6343a6356b..3484a393c66 100644 --- a/frameworks/Java/vertx-web/vertx-web-postgres.dockerfile +++ b/frameworks/Java/vertx-web/vertx-web-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 as maven +FROM maven:3.9.11-eclipse-temurin-25 as maven WORKDIR /vertx-web COPY scripts scripts COPY src src @@ -23,7 +23,7 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -jar \ - target/vertx-web-benchmark-4.3.8-fat.jar \ + target/vertx-web-benchmark-5.0.5-fat.jar \ --instances \ `grep --count ^processor /proc/cpuinfo` \ --conf \ diff --git a/frameworks/Java/vertx-web/vertx-web.dockerfile b/frameworks/Java/vertx-web/vertx-web.dockerfile index a6343a6356b..3484a393c66 100644 --- a/frameworks/Java/vertx-web/vertx-web.dockerfile +++ b/frameworks/Java/vertx-web/vertx-web.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 as maven +FROM maven:3.9.11-eclipse-temurin-25 as maven WORKDIR /vertx-web COPY scripts scripts COPY src src @@ -23,7 +23,7 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -jar \ - target/vertx-web-benchmark-4.3.8-fat.jar \ + target/vertx-web-benchmark-5.0.5-fat.jar \ --instances \ `grep --count ^processor /proc/cpuinfo` \ --conf \ diff --git a/frameworks/Java/vertx/benchmark_config.json b/frameworks/Java/vertx/benchmark_config.json index 27064691b03..dc829a23ab0 100755 --- a/frameworks/Java/vertx/benchmark_config.json +++ b/frameworks/Java/vertx/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "vertx", + "maintainers": ["vietj", "tsegismont"], "tests": [{ "default": { "json_url": "/json", diff --git a/frameworks/Java/vertx/pom.xml b/frameworks/Java/vertx/pom.xml index 06fd8183ed5..3a5f63f1a88 100644 --- a/frameworks/Java/vertx/pom.xml +++ b/frameworks/Java/vertx/pom.xml @@ -10,7 +10,7 @@ 17 vertx.App - 5.0.4 + 5.0.7 4.2.5.Final 2.16.1 diff --git a/frameworks/Java/vertx/src/main/java/vertx/App.java b/frameworks/Java/vertx/src/main/java/vertx/App.java index f2d54510503..039e2ee905a 100755 --- a/frameworks/Java/vertx/src/main/java/vertx/App.java +++ b/frameworks/Java/vertx/src/main/java/vertx/App.java @@ -86,13 +86,11 @@ static int getQueries(HttpServerRequest request) { private static final CharSequence HEADER_CONTENT_TYPE = HttpHeaders.CONTENT_TYPE; private static final CharSequence HEADER_CONTENT_LENGTH = HttpHeaders.CONTENT_LENGTH; - private static final CharSequence HELLO_WORLD_LENGTH = HttpHeaders.createOptimized("" + HELLO_WORLD.length()); - private static final CharSequence JSON_LENGTH = HttpHeaders.createOptimized("" + new Message("Hello, World!").toJson().length()); private static final CharSequence SERVER = HttpHeaders.createOptimized("vert.x"); - private static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; - private static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE"; - private static final String SELECT_WORLDS = "SELECT id, randomnumber from WORLD"; + private static final String SELECT_WORLD = "SELECT id, randomnumber FROM world WHERE id = $1"; + private static final String SELECT_FORTUNE = "SELECT id, message FROM fortune"; + private static final String SELECT_WORLDS = "SELECT id, randomnumber FROM world"; public static CharSequence createDateHeader() { return HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); @@ -132,7 +130,6 @@ private MultiMap plaintextHeaders() { .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_PLAIN) .add(HEADER_SERVER, SERVER) .add(HEADER_DATE, dateString) - .add(HEADER_CONTENT_LENGTH, HELLO_WORLD_LENGTH) .copy(false); } @@ -142,7 +139,6 @@ private MultiMap jsonHeaders() { .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON) .add(HEADER_SERVER, SERVER) .add(HEADER_DATE, dateString) - .add(HEADER_CONTENT_LENGTH, JSON_LENGTH) .copy(false); } @@ -213,12 +209,12 @@ private Future initClients(PgConnectOptions options) { private static String buildAggregatedUpdateQuery(int len) { StringBuilder sql = new StringBuilder(); - sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID"); + sql.append("UPDATE world SET randomnumber = CASE ID"); for (int i = 0; i < len; i++) { int offset = (i * 2) + 1; sql.append(" WHEN $").append(offset).append(" THEN $").append(offset + 1); } - sql.append(" ELSE RANDOMNUMBER"); + sql.append(" ELSE randomnumber"); sql.append(" END WHERE ID IN ($1"); for (int i = 1; i < len; i++) { int offset = (i * 2) + 1; @@ -304,12 +300,12 @@ private void handleDb(HttpServerRequest req) { return; } Row row = resultSet.next(); - World word = new World(row.getInteger(0), row.getInteger(1)); + World world = new World(row.getInteger(0), row.getInteger(1)); MultiMap headers = resp.headers(); headers.add(HttpHeaders.SERVER, SERVER); headers.add(HttpHeaders.DATE, dateString); headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON); - resp.end(word.toJson()); + resp.end(world.toJson()); } else { sendError(req, res.cause()); } diff --git a/frameworks/Java/voovan/benchmark_config.json b/frameworks/Java/voovan/benchmark_config.json index bc2c30a9159..13daab795ed 100644 --- a/frameworks/Java/voovan/benchmark_config.json +++ b/frameworks/Java/voovan/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "voovan-mvc", "notes": "voovan webserver with mvc", - "versus": "voovan" + "versus": "" } }] } diff --git a/frameworks/Java/voovan/config.toml b/frameworks/Java/voovan/config.toml index fb05912f86b..c882915db4e 100644 --- a/frameworks/Java/voovan/config.toml +++ b/frameworks/Java/voovan/config.toml @@ -12,4 +12,4 @@ os = "Linux" orm = "None" platform = "Voovan" webserver = "None" -versus = "voovan" +versus = "" diff --git a/frameworks/Java/wizzardo-http/benchmark_config.json b/frameworks/Java/wizzardo-http/benchmark_config.json index 60ad3d406b7..d3fe94fd919 100644 --- a/frameworks/Java/wizzardo-http/benchmark_config.json +++ b/frameworks/Java/wizzardo-http/benchmark_config.json @@ -23,7 +23,8 @@ "database_os": "Linux", "display_name": "wizzardo-http", "notes": "", - "versus": "" + "versus": "", + "tags": ["broken"] } } ] diff --git a/frameworks/JavaScript/es4x/benchmark_config.json b/frameworks/JavaScript/es4x/benchmark_config.json index 85e28868b5a..17677bef092 100755 --- a/frameworks/JavaScript/es4x/benchmark_config.json +++ b/frameworks/JavaScript/es4x/benchmark_config.json @@ -23,7 +23,8 @@ "database_os": "Linux", "display_name": "ES4X", "notes": "", - "versus": "nodejs" + "versus": "nodejs", + "tags": ["broken"] } } ] diff --git a/frameworks/JavaScript/express/app.js b/frameworks/JavaScript/express/app.js index 9f1039e2179..ed39eae5222 100755 --- a/frameworks/JavaScript/express/app.js +++ b/frameworks/JavaScript/express/app.js @@ -7,7 +7,11 @@ const cluster = require('cluster'), numCPUs = require('os').cpus().length, express = require('express'); -const bodyParser = require('body-parser'); +const { + jsonSerializer, + GREETING, +} = require("./src/utils.mjs"); + if (cluster.isPrimary) { console.log(`Primary ${process.pid} is running`); @@ -23,24 +27,27 @@ if (cluster.isPrimary) { } else { const app = module.exports = express(); - // Configuration - app.use(bodyParser.urlencoded({ extended: true })); - - // Set headers for all routes - app.use((req, res, next) => { - res.setHeader("Server", "Express"); - return next(); - }); - - app.set('view engine', 'jade'); - app.set('views', __dirname + '/views'); + app.set('x-powered-by', false); + app.set('etag', false); // Routes - app.get('/json', (req, res) => res.send({ message: 'Hello, World!' })); + app.get('/json', (req, res) => { + res.writeHead(200, { + "content-type": "application/json", + server: "Express", + }).end(jsonSerializer({ message: GREETING })) + }); - app.get('/plaintext', (req, res) => - res.header('Content-Type', 'text/plain').send('Hello, World!')); + app.get('/plaintext', (req, res) => { + res.writeHead(200, { + "content-type": "text/plain", + server: "Express", + }).end(GREETING); + }); const server = app.listen(8080); server.keepAliveTimeout = 0; + server.headersTimeout = 0; + server.requestTimeout = 0; + server.maxConnections = Infinity; } diff --git a/frameworks/JavaScript/express/benchmark_config.json b/frameworks/JavaScript/express/benchmark_config.json index 9f04d0dd56e..74e54eb7876 100644 --- a/frameworks/JavaScript/express/benchmark_config.json +++ b/frameworks/JavaScript/express/benchmark_config.json @@ -34,7 +34,7 @@ "orm": "Full", "os": "Linux", "database_os": "Linux", - "display_name": "express", + "display_name": "express[mongoose]", "notes": "", "versus": "nodejs" }, @@ -86,6 +86,7 @@ "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", + "cached_query_url": "/cached-worlds?count=", "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", @@ -104,4 +105,4 @@ "versus": "nodejs" } }] -} \ No newline at end of file +} diff --git a/frameworks/JavaScript/express/express-mongodb.dockerfile b/frameworks/JavaScript/express/express-mongodb.dockerfile index fdd130d3195..a7252b75e1d 100644 --- a/frameworks/JavaScript/express/express-mongodb.dockerfile +++ b/frameworks/JavaScript/express/express-mongodb.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express-mysql.dockerfile b/frameworks/JavaScript/express/express-mysql.dockerfile index f446c93d2f4..0040ce7e72e 100644 --- a/frameworks/JavaScript/express/express-mysql.dockerfile +++ b/frameworks/JavaScript/express/express-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express-postgres.dockerfile b/frameworks/JavaScript/express/express-postgres.dockerfile index 46cf427d0a2..1bf66cd1884 100644 --- a/frameworks/JavaScript/express/express-postgres.dockerfile +++ b/frameworks/JavaScript/express/express-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express-postgresjs.dockerfile b/frameworks/JavaScript/express/express-postgresjs.dockerfile index bc570d57faf..e3491ca56d6 100644 --- a/frameworks/JavaScript/express/express-postgresjs.dockerfile +++ b/frameworks/JavaScript/express/express-postgresjs.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express.dockerfile b/frameworks/JavaScript/express/express.dockerfile index ec726dd2800..8c47bfc4695 100644 --- a/frameworks/JavaScript/express/express.dockerfile +++ b/frameworks/JavaScript/express/express.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/graphql-mongodb-app.js b/frameworks/JavaScript/express/graphql-mongodb-app.js deleted file mode 100644 index 4e02143a2c4..00000000000 --- a/frameworks/JavaScript/express/graphql-mongodb-app.js +++ /dev/null @@ -1,37 +0,0 @@ -const cluster = require('cluster') -const numCPUs = require('os').cpus().length -const express = require('express'); -const mongoose = require('mongoose'); -const app = express(); -const bodyParser = require('body-parser'); -const port = 8080; - -mongoose.Promise = global.Promise; - -mongoose.connect('mongodb://tfb-database/hello_world').then(() => { - console.log('connected to mongo tfb-database hello_world'); -}).catch((err) => { - console.log('Failed connection attempt to Mongo: ', err); -}); - -if (cluster.isPrimary) { - // Fork workers. - for (let i = 0; i < numCPUs; i++) { - cluster.fork(); - } - - cluster.on('exit', (worker, code, signal) => - console.log('worker ' + worker.pid + ' died')); -} else { - app.use(bodyParser.urlencoded({ extended:false })); - app.use(bodyParser.json()); - - const resolvers = require('./resolver-mongo'); - - // Routes - require('/routes.js')(app, resolvers); - - app.listen(port, () => { - console.log(`Listening on localhost:${port}`); - }); -} diff --git a/frameworks/JavaScript/express/graphql-mysql-app.js b/frameworks/JavaScript/express/graphql-mysql-app.js deleted file mode 100644 index d63e9c3fd70..00000000000 --- a/frameworks/JavaScript/express/graphql-mysql-app.js +++ /dev/null @@ -1,28 +0,0 @@ -const cluster = require('cluster') -const numCPUs = require('os').cpus().length -const express = require('express'); -const app = express(); -const bodyParser = require('body-parser'); -const port = 8080; - -if (cluster.isPrimary) { - // Fork workers. - for (let i = 0; i < numCPUs; i++) { - cluster.fork(); - } - - cluster.on('exit', (worker, code, signal) => - console.log('worker ' + worker.pid + ' died')); -} else { - app.use(bodyParser.urlencoded({ extended:false })); - app.use(bodyParser.json()); - - const resolvers = require('./resolver'); - - // Routes - require('./routes')(app, resolvers); - - app.listen(port, () => { - console.log(`Listening on localhost:${port}`); - }); -} diff --git a/frameworks/JavaScript/express/graphql-postgres-app.js b/frameworks/JavaScript/express/graphql-postgres-app.js deleted file mode 100644 index f05490fcabc..00000000000 --- a/frameworks/JavaScript/express/graphql-postgres-app.js +++ /dev/null @@ -1,29 +0,0 @@ -const cluster = require('cluster') -const numCPUs = require('os').cpus().length -const express = require('express'); -const app = express(); -const bodyParser = require('body-parser'); -const port = 8080; - -if (cluster.isPrimary) { - // Fork workers. - for (let i = 0; i < numCPUs; i++) { - cluster.fork(); - } - - cluster.on('exit', (worker, code, signal) => - console.log('worker ' + worker.pid + ' died')); -} else { - - app.use(bodyParser.urlencoded({ extended:false })); - app.use(bodyParser.json()); - - const resolvers = require('./resolver-postgres'); - - // Routes - require('./routes')(app, resolvers); - - app.listen(port, () => { - console.log(`Listening on localhost:${port}`); - }); -} diff --git a/frameworks/JavaScript/express/helper.js b/frameworks/JavaScript/express/helper.js index 24faf721309..e454f44ebfa 100644 --- a/frameworks/JavaScript/express/helper.js +++ b/frameworks/JavaScript/express/helper.js @@ -1,20 +1,10 @@ module.exports = { sanititizeTotal : (total) => { - let totalIterations; - if (!total || typeof(total) != 'number') { - totalIterations = 1; - } else if(total < 501 && total > 0) { - totalIterations = total; - } else if (total > 500) { - totalIterations = 500; - } else { - totalIterations = 1; - } - return totalIterations; + return total > 500 ? 500 : (i | 0) || 1; }, randomizeNum : () => { - return Math.floor(Math.random() * 10000) + 1 + return ((Math.random() * 10000) | 0) + 1; } } \ No newline at end of file diff --git a/frameworks/JavaScript/express/mongodb-app.js b/frameworks/JavaScript/express/mongodb-app.js index 534fddc63f5..de9c0901395 100644 --- a/frameworks/JavaScript/express/mongodb-app.js +++ b/frameworks/JavaScript/express/mongodb-app.js @@ -8,9 +8,6 @@ const express = require('express'); const mongoose = require('mongoose'); const connection = mongoose.createConnection('mongodb://tfb-database/hello_world'); -// Middleware -const bodyParser = require('body-parser'); - /** * Note! The benchmarks say we should use "id" as a property name. * However, Mongo provides a default index on "_id", so to be equivalent to the other tests, we use @@ -43,6 +40,9 @@ if (cluster.isPrimary) { } else { const app = module.exports = express(); + app.set('x-powered-by', false); + app.set('etag', false) + const randomTfbNumber = () => Math.floor(Math.random() * 10000) + 1; const toClientWorld = (world) => { if (world) { @@ -52,15 +52,6 @@ if (cluster.isPrimary) { return world; }; - // Configuration - app.use(bodyParser.urlencoded({extended: true})); - - // Set headers for all routes - app.use((req, res, next) => { - res.setHeader("Server", "Express"); - return next(); - }); - app.set('view engine', 'pug'); app.set('views', __dirname + '/views'); @@ -77,12 +68,13 @@ if (cluster.isPrimary) { promises.push(getRandomWorld()); } + res.setHeader("Server", "Express"); res.send(await Promise.all(promises)); }); app.get('/mongoose', async (req, res) => { const result = await MWorld.findOne({_id: randomTfbNumber()}).lean().exec(); - + res.setHeader("Server", "Express"); res.send(toClientWorld(result)); }); @@ -91,7 +83,7 @@ if (cluster.isPrimary) { const newFortune = {id: 0, message: "Additional fortune added at request time."}; fortunes.push(newFortune); fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); - + res.setHeader("Server", "Express"); res.render('fortunes/index', {fortunes}); }); @@ -111,14 +103,16 @@ if (cluster.isPrimary) { app.get('/mongoose-update', async (req, res) => { const queryCount = Math.min(parseInt(req.query.queries, 10) || 1, 500); - const promises = []; + const promises = new Array(queryCount); for (let i = 1; i <= queryCount; i++) { - promises.push(getUpdateRandomWorld()); + promises[i - 1] = getUpdateRandomWorld(); } + res.setHeader("Server", "Express"); res.send(await Promise.all(promises)); }); - app.listen(8080); + const server = app.listen(8080); + server.keepAliveTimeout = 0; } diff --git a/frameworks/JavaScript/express/mysql-app.js b/frameworks/JavaScript/express/mysql-app.js index 7e277f0e695..58cfdf32554 100644 --- a/frameworks/JavaScript/express/mysql-app.js +++ b/frameworks/JavaScript/express/mysql-app.js @@ -8,9 +8,6 @@ const cluster = require('cluster'), express = require('express'), Sequelize = require('sequelize'); -// Middleware -const bodyParser = require('body-parser'); - const sequelize = new Sequelize('hello_world', 'benchmarkdbuser', 'benchmarkdbpass', { host: 'tfb-database', dialect: 'mysql', @@ -59,23 +56,17 @@ if (cluster.isPrimary) { } else { const app = module.exports = express(); - // Configuration - // https://github.com/expressjs/method-override#custom-logic - app.use(bodyParser.urlencoded({ extended: true })); - - // Set headers for all routes - app.use((req, res, next) => { - res.setHeader("Server", "Express"); - return next(); - }); + app.set('x-powered-by', false); + app.set('etag', false) app.set('view engine', 'pug'); app.set('views', __dirname + '/views'); // Routes app.get('/mysql-orm-query', async (req, res) => { - const results = [], - queries = Math.min(parseInt(req.query.queries) || 1, 500); + + const queries = Math.min(parseInt(req.query.queries) || 1, 500); + const results = new Array(queries); for (let i = 1; i <= queries; i++) { const world = await World.findOne({ @@ -84,10 +75,11 @@ if (cluster.isPrimary) { } } ); - results.push(world); + results[i - 1] = world; } res.setHeader("Content-Type", "application/json"); + res.setHeader("Server", "Express"); res.send(results); }); @@ -100,22 +92,23 @@ if (cluster.isPrimary) { ); res.setHeader("Content-Type", "application/json"); + res.setHeader("Server", "Express"); res.send(world) }); - app.get('/mysql-orm-fortune', (req, res) => { - Fortune.findAll().then((fortunes) => { - const newFortune = { id: 0, message: "Additional fortune added at request time." }; - fortunes.push(newFortune); - fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); + app.get('/mysql-orm-fortune', async(req, res) => { + const fortunes = await Fortune.findAll() + const newFortune = { id: 0, message: "Additional fortune added at request time." }; + fortunes.push(newFortune); + fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); - res.render('fortunes/index', { fortunes: fortunes }); - }); + res.setHeader("Server", "Express"); + res.render('fortunes/index', { fortunes: fortunes }); }); app.get('/mysql-orm-update', async (req, res) => { - const results = [], - queries = Math.min(parseInt(req.query.queries) || 1, 500); + const queries = Math.min(parseInt(req.query.queries) || 1, 500); + const results = new Array(queries); for (let i = 1; i <= queries; i++) { const world = await World.findOne({ @@ -126,11 +119,13 @@ if (cluster.isPrimary) { ); world.randomNumber = ~~(Math.random() * 10000) + 1; await world.save(); - results.push(world); + results[i - 1] = world; } + res.setHeader("Server", "Express"); res.send(results); }); - app.listen(8080); + const server = app.listen(8080); + server.keepAliveTimeout = 0; } diff --git a/frameworks/JavaScript/express/package.json b/frameworks/JavaScript/express/package.json index 143da144588..236bf500258 100644 --- a/frameworks/JavaScript/express/package.json +++ b/frameworks/JavaScript/express/package.json @@ -3,17 +3,15 @@ "version": "0.0.1", "private": true, "dependencies": { - "body-parser": "1.20.3", - "dateformat": "3.0.3", - "escape-html": "1.0.3", - "express": "4.18.2", - "mongoose": "8.9.5", - "mysql2": "3.9.8", - "pg": "8.5.0", - "pg-promise": "11.5.5", + "express": "5.2.1", + "fast-json-stringify": "^6.3.0", + "lru-cache": "^11.2.6", + "mongoose": "9.2.4", + "mysql2": "3.18.2", + "pg": "8.19.0", + "pg-promise": "12.6.1", + "postgres": "^3.4.8", "pug": "3.0.3", - "postgres": "^3.4.3", - "slow-json-stringify": "^2.0.1", - "sequelize": "6.29.0" + "sequelize": "6.37.8" } } diff --git a/frameworks/JavaScript/express/postgresql-app.js b/frameworks/JavaScript/express/postgresql-app.js index 38d1cfbdb7d..74bbda75d61 100644 --- a/frameworks/JavaScript/express/postgresql-app.js +++ b/frameworks/JavaScript/express/postgresql-app.js @@ -6,9 +6,6 @@ const cluster = require('cluster'), express = require('express'), helper = require('./helper'); -// Middleware -const bodyParser = require('body-parser'); - const Sequelize = require('sequelize'); const sequelize = new Sequelize('hello_world', 'benchmarkdbuser', 'benchmarkdbpass', { host: 'tfb-database', @@ -46,9 +43,7 @@ const Fortunes = sequelize.define('fortune', { const randomWorldPromise = () => { return Worlds.findOne({ where: { id: helper.randomizeNum() } - }).then((results) => { - return results; - }).catch((err) => process.exit(1)); + }); }; if (cluster.isPrimary) { @@ -62,13 +57,8 @@ if (cluster.isPrimary) { } else { const app = module.exports = express(); - app.use(bodyParser.urlencoded({ extended: true })); - - // Set headers for all routes - app.use((req, res, next) => { - res.setHeader("Server", "Express"); - return next(); - }); + app.set('x-powered-by', false); + app.set('etag', false) app.set('view engine', 'pug'); app.set('views', __dirname + '/views'); @@ -78,6 +68,7 @@ if (cluster.isPrimary) { let world = await randomWorldPromise(); res.setHeader("Content-Type", "application/json"); + res.setHeader("Server", "Express"); res.json(world); }); @@ -90,6 +81,7 @@ if (cluster.isPrimary) { promisesArray.push(randomWorldPromise()); } + res.setHeader("Server", "Express"); res.json(await Promise.all(promisesArray)) }); @@ -99,6 +91,7 @@ if (cluster.isPrimary) { fortunes.push(newFortune); fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); + res.setHeader("Server", "Express"); res.render('fortunes/index', { fortunes: fortunes }); }); @@ -110,29 +103,30 @@ if (cluster.isPrimary) { worldPromises.push(randomWorldPromise()); } - const worldUpdate = (world) => { + const worldUpdate = async(world) => { world.randomnumber = helper.randomizeNum(); - return Worlds.update({ - randomnumber: world.randomnumber - }, - { - where: { id: world.id } - }).then((results) => { - return world; - }).catch((err) => process.exit(1)); + await Worlds.update({ + randomnumber: world.randomnumber + }, + { + where: { id: world.id } + }); + return world; }; - Promise.all(worldPromises).then((worlds) => { - const updates = worlds.map((e) => worldUpdate(e)); + const worlds = await Promise.all(worldPromises); + + const updates = worlds.map((e) => worldUpdate(e)); - Promise.all(updates).then((updated) => { - res.json(updated); - }); - }); + const updated = await Promise.all(updates); + + res.setHeader("Server", "Express"); + res.json(updated); }); - app.listen(8080, () => { + const server = app.listen(8080, () => { console.log('listening on port 8080'); }); + server.keepAliveTimeout = 0; } diff --git a/frameworks/JavaScript/express/resolver-mongo.js b/frameworks/JavaScript/express/resolver-mongo.js index 6d7aed41d2a..413e88f7344 100644 --- a/frameworks/JavaScript/express/resolver-mongo.js +++ b/frameworks/JavaScript/express/resolver-mongo.js @@ -31,15 +31,15 @@ async function getRandomWorld() { // Methods -async function arrayOfRandomWorlds(totalWorldsToReturn) { +function arrayOfRandomWorlds(totalWorldsToReturn) { const totalIterations = helper.sanititizeTotal(totalWorldsToReturn); - const promises = []; + const promises = new Array(totalIterations); for (let i = 1; i <= totalIterations; i++) { - promises.push(getRandomWorld()); + promises[i - 1] = getRandomWorld(); } - return await Promise.all(promises); + return Promise.all(promises); } async function getAndUpdateRandomWorld() { @@ -56,15 +56,15 @@ async function getAndUpdateRandomWorld() { return toClientWorld(world); } -async function updateRandomWorlds(totalToUpdate) { +function updateRandomWorlds(totalToUpdate) { const totalIterations = helper.sanititizeTotal(totalToUpdate); - const promises = []; + const promises = new Array(totalIterations); for (let i = 1; i <= totalIterations; i++) { - promises.push(getAndUpdateRandomWorld()); + promises[i - 1] = getAndUpdateRandomWorld(); } - return await Promise.all(promises); + return Promise.all(promises); } const sayHello = () => { @@ -81,14 +81,13 @@ module.exports = { multipleDatabaseQueries: async (parent, args) => await arrayOfRandomWorlds(args.total), getWorldById: async (parent, args) => toClientWorld(await World.findById(args.id).lean().exec()), getAllFortunes: async () => toClientWorld(await Fortune.find({}).lean().exec()), - getRandomAndUpdate: async (parent, args) => await updateRandomWorlds(args.total) + getRandomAndUpdate: (parent, args) => updateRandomWorlds(args.total) }, Mutation: { - createWorld: async (parent, args) => { - const randInt = helper.randomizeNum(); - return await World.create({_id: null, randomNumber: randInt}); + createWorld: (parent, args) => { + return World.create({_id: null, randomNumber: helper.randomizeNum()}); }, - updateWorld: async (parent, args) => { + updateWorld: (parent, args) => { return World.updateOne({_id: args.id}, { randomNumber: args.randomNumber }).exec(); diff --git a/frameworks/JavaScript/express/resolver-postgres.js b/frameworks/JavaScript/express/resolver-postgres.js index 3fc272e1533..95d401f2592 100644 --- a/frameworks/JavaScript/express/resolver-postgres.js +++ b/frameworks/JavaScript/express/resolver-postgres.js @@ -13,35 +13,28 @@ const connection = { const db = pgp(`postgres://${connection.username}:${connection.password}@${connection.host}:5432/${connection.db}`); -async function arrayOfRandomWorlds(totalWorldsToReturn) { +function arrayOfRandomWorlds(totalWorldsToReturn) { - var totalIterations = helper.sanititizeTotal(totalWorldsToReturn); - var arr = []; + const totalIterations = helper.sanititizeTotal(totalWorldsToReturn); + const arr = new Array(totalIterations); - return new Promise(async(resolve, reject) => { + for(let i = 0; i < totalIterations; i++) { + arr[i] = getRandomWorld(); + } - for(var i = 0; i < totalIterations; i++) { - arr.push(await getRandomWorld()); - } - - if(arr.length == totalIterations) { - resolve(arr); - } - }); + return Promise.all(arr); }; -async function updateRandomWorlds(totalToUpdate) { +function updateRandomWorlds(totalToUpdate) { const total = helper.sanititizeTotal(totalToUpdate); - var arr = []; + const arr = new Array(total); - return new Promise(async(resolve, reject) => { - for(var i = 0; i < total; i++) { - arr.push(await updateRandomWorld()); - } + for(let i = 0; i < total; i++) { + arr[i] = updateRandomWorld(); + } - if(arr.length === total) resolve(arr) - }); + return Promise.all(arr); }; const getRandomWorld = async () => { @@ -56,25 +49,24 @@ const updateRandomWorld = async () => { return {"id": world.id, "randomNumber": world.randomnumber}; }; -const getAllFortunes = async () => { - - return await db.many('select * from fortune', [true]); +const getAllFortunes = () => { + return db.many('select * from fortune', [true]); }; module.exports = { Query: { - singleDatabaseQuery: async() => await getRandomWorld(), - multipleDatabaseQueries: async(parent, args) => await arrayOfRandomWorlds(args.total), - getAllFortunes: async() => await getAllFortunes(), - getRandomAndUpdate: async(parent, args) => await updateRandomWorlds(args.total) + singleDatabaseQuery: () => getRandomWorld(), + multipleDatabaseQueries: (parent, args) => arrayOfRandomWorlds(args.total), + getAllFortunes: () => getAllFortunes(), + getRandomAndUpdate: (parent, args) => updateRandomWorlds(args.total) }, Mutation: { - createWorld: async(parent, args) => { + createWorld: (parent, args) => { let randInt = Math.floor(Math.random() * 1000) + 1; - return await World.create({ id: null, randomNumber: randInt }); + return World.create({ id: null, randomNumber: randInt }); }, - updateWorld: async(parent, args) => { - return await World.update({id: args.id, randomNumber: args.randomNumber}); + updateWorld: (parent, args) => { + return World.update({id: args.id, randomNumber: args.randomNumber}); } } } \ No newline at end of file diff --git a/frameworks/JavaScript/express/resolver.js b/frameworks/JavaScript/express/resolver.js index f396f502441..a3f7acec4dc 100644 --- a/frameworks/JavaScript/express/resolver.js +++ b/frameworks/JavaScript/express/resolver.js @@ -48,67 +48,62 @@ const Fortune = sequelize.define('fortune', { freezeTableName: true }); -async function arrayOfRandomWorlds(totalWorldToReturn) { +function arrayOfRandomWorlds(totalWorldToReturn) { - var totalIterations = helper.sanititizeTotal(totalWorldToReturn); - var arr = []; + const totalIterations = helper.sanititizeTotal(totalWorldToReturn); + const arr = new Array(); - return new Promise(async (resolve, reject) => { - for(var i = 0; i < totalIterations; i++) { - let world = await World.findByPk(helper.randomizeNum()); - arr.push(world); - } - if(arr.length == totalIterations) { - resolve(arr); - } - }); + for(let i = 0; i < totalIterations; i++) { + arr[i] = World.findByPk(helper.randomizeNum()); + } + + return Promise.all(arr); }; async function updateRandomWorlds(totalToUpdate) { const total = helper.sanititizeTotal(totalToUpdate); - var arr = []; + const arr = new Array(total); - return new Promise(async (resolve, reject) => { - for(var i = 0; i < total; i++) { + for(let i = 0; i < total; i++) { + arr[i] = World.findByPk(helper.randomizeNum()); + } - const world = await World.findByPk(helper.randomizeNum()); - world.updateAttributes({ - randomNumber: helper.randomizeNum() - }) - arr.push(world); - } - if(arr.length == total) { - resolve(arr); - } - }); -}; + const results = await Promise.all(arr); -const sayHello = () => { + const updates = new Array(total); + for (let index = 0; index < results.length; index++) { + const element = results[index]; + updates[index] = element.updateAttributes({ + randomNumber: helper.randomizeNum() + }); + } - var helloWorld = new Object; - helloWorld.message = "Hello, World!"; + await Promise.all(updates); - return JSON.stringify(helloWorld); + return results; +} + +const sayHello = () => { + return JSON.stringify({ message:"Hello, World!" }); }; module.exports = { Query: { helloWorld: () => sayHello(), - getAllWorlds: async() => await World.findAll(), - singleDatabaseQuery: async() => await World.findByPk(helper.randomizeNum()), - multipleDatabaseQueries: async(parent, args) => await arrayOfRandomWorlds(args.total), - getWorldById: async(parent, args) => await World.findByPk(args.id), - getAllFortunes: async() => await Fortune.findAll(), - getRandomAndUpdate: async(parent, args) => await updateRandomWorlds(args.total) + getAllWorlds: () => World.findAll(), + singleDatabaseQuery: () => World.findByPk(helper.randomizeNum()), + multipleDatabaseQueries: (parent, args) => arrayOfRandomWorlds(args.total), + getWorldById: (parent, args) => World.findByPk(args.id), + getAllFortunes: () => Fortune.findAll(), + getRandomAndUpdate: (parent, args) => updateRandomWorlds(args.total) }, Mutation: { - createWorld: async(parent, args) => { - let randInt = Math.floor(Math.random() * 1000) + 1; - return await World.create({ id: null, randomNumber: randInt }); + createWorld: (parent, args) => { + return World.create({ id: null, randomNumber: Math.floor(Math.random() * 1000) + 1 }); }, - updateWorld: async(parent, args) => { - return await World.update({id: args.id, randomNumber: args.randomNumber}); + updateWorld: (parent, args) => { + return World.update({id: args.id, randomNumber: args.randomNumber}); } } } diff --git a/frameworks/JavaScript/express/routes.js b/frameworks/JavaScript/express/routes.js deleted file mode 100644 index 3919fe1c6f5..00000000000 --- a/frameworks/JavaScript/express/routes.js +++ /dev/null @@ -1,253 +0,0 @@ -const graphqlHTTP = require('express-graphql'); -const escape = require('escape-html'); -const dateFormat = require('dateformat'); -const { makeExecutableSchema } = require('graphql-tools'); - -module.exports = (app, resolvers) => { - - const typeDefs = require('./schema'); - - const schema = makeExecutableSchema({ - typeDefs, - resolvers - }); - - app.get('/json', async(req, res) => { - - const graphql = await graphqlHTTP((req, res, graphQLParams) => { - - graphQLParams.query = "{ helloWorld }"; - graphQLParams.operationName = null; - graphQLParams.variables = {}; - - return graphqlOpts() - }); - - res.real_end = res.end; - - res.end = (data) => { - - let toRet; - const json = JSON.parse(data.toString('utf8')); - - if(json.data.helloWorld) { - toRet = json.data.helloWorld; - } else { - toRet = { helloWorld: null }; - } - - setResponseHeaders(res, toRet.length); - - res.real_end(toRet); - } - - await graphql(req, res); - }); - - app.get('/db', async (req, res) => { - - const graphql = await graphqlHTTP((req, res, graphQLParams) => { - - graphQLParams.query = "{ singleDatabaseQuery { id, randomNumber }}"; - graphQLParams.variables = {}; - graphQLParams.operationName = null; - - return graphqlOpts(); - }); - - formatResData(res, "singleDatabaseQuery"); - - await graphql(req, res); - }); - - app.get('/queries', async (req, res) => { - - const graphql = await graphqlHTTP((req, res, graphQLParams) => { - - let totalNumOfQueries = ensureQueryIsAnInt(req.query.queries); - - graphQLParams.query = `{ multipleDatabaseQueries(total: ${totalNumOfQueries}) { id, randomNumber }}` - graphQLParams.variables = {}; - graphQLParams.operationName = null; - - return graphqlOpts(); - }); - - formatResData(res, "multipleDatabaseQueries"); - - await graphql(req, res); - }); - - app.get('/fortunes', async (req, res) => { - - const graphql = await graphqlHTTP((req, res, graphQLParams) => { - - graphQLParams.query = "{ getAllFortunes { id, message } }" - graphQLParams.operationName = null; - graphQLParams.variables = {}; - - return graphqlOpts(); - }); - - retrieveAndFormatAllFortunes(res); - - await graphql(req, res); - }); - - app.get('/updates', async (req, res) => { - - const totalNumOfQueries = ensureQueryIsAnInt(req.query.queries); - - const graphql = await graphqlHTTP((req, res, graphQLParams) => { - - graphQLParams.query = `{ getRandomAndUpdate(total: ${totalNumOfQueries}) { id, randomNumber } }` - graphQLParams.operationName = null; - graphQLParams.variables = {}; - - return graphqlOpts(); - }); - - formatResData(res, 'getRandomAndUpdate'); - - await graphql(req, res); - }); - - app.get('/plaintext', (req, res) => { - - const responseTxt = "Hello, World!"; - - res.setHeader('Content-Length', responseTxt.length); - res.setHeader('Server', 'Express-GraphQL-MySQL'); - res.contentType('text/plain'); - res.status(200); - - res.send(responseTxt); - }); - - // Helper Functions - - const ensureQueryIsAnInt = (queryString) => { - - if(queryString === undefined) return 1; - - const possibleInt = parseInt(queryString); - if(!possibleInt) return 1; - - return possibleInt; - }; - - const graphqlOpts = (params) => { - return { - schema, - graphiql: false, - context: params || {} - } - }; - - const retrieveAndFormatAllFortunes = res => { - - res.real_end = res.end; - - res.end = async (data) => { - let toRet; - const json = JSON.parse(data.toString('utf8')); - - if(json.data.getAllFortunes) { - toRet = json.data.getAllFortunes; - } else { - toRet = []; - } - - const newFortune = { "id": 0, "message": "Additional fortune added at request time." }; - toRet.push(newFortune); - toRet.sort((a, b) => (a.message < b.message) ? -1 : 1); - - const htmlToRet = await spoofHTML(toRet); - - res.contentType('html'); - res.setHeader('Server', 'GraphQL-MySQL'); - res.setHeader('Content-Length', htmlToRet.length + 32); - res.status(200); - - res.real_end(htmlToRet); - } - }; - - const spoofHTML = arr => { - - return new Promise((resolve, reject) => { - - let count = 0; - - let htmlToRet = `Fortunes`; - - for (let fortune of arr) { - - htmlToRet += ``; - count++; - } - - htmlToRet += '
idmessage
${escape(fortune.id)}${escape(fortune.message)}
'; - - if(count == arr.length)resolve(htmlToRet); - - }); - }; - - const formatResData = (res, queryName) => { - - res.real_end = res.end; - - res.end = (data) => { - - const json = JSON.parse(data.toString('utf8')); - - let toRet = formatJson(queryName, json); - - const jsonToRet = JSON.stringify(toRet); - - setResponseHeaders(res, jsonToRet.length); - - res.real_end(jsonToRet); - }; - }; - - const formatJson = (queryName, jsonData) => { - - const isQueryReturningAnArray = { - - singleDatabaseQuery: false, - multipleDatabaseQueries: true, - getRandomAndUpdate: true - }; - - if (isQueryReturningAnArray[queryName] == false) { - - if(jsonData.data[`${queryName}`]) { - return { - id: jsonData.data[`${queryName}`].id, - randomNumber: jsonData.data[`${queryName}`].randomNumber - }; - } else { - return { - id: null, - randomNumber: null - } - } - } else { - - return jsonData.data[`${queryName}`] || []; - } - }; - - const setResponseHeaders = (res, jsonLength) => { - - let now = new Date(); - - res.status(200); - res.contentType('application/json', 'charset=UTF-8'); - res.setHeader('Date', dateFormat(now, "ddd, dd mmm yyyy hh:MM:ss Z")); - res.setHeader('Server', 'GraphQL-Express-MySQL'); - res.setHeader('Content-Length', jsonLength); - }; -} diff --git a/frameworks/JavaScript/express/schema.js b/frameworks/JavaScript/express/schema.js deleted file mode 100644 index 292243e18da..00000000000 --- a/frameworks/JavaScript/express/schema.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = ` - type Query { - getWorldById(id:Int!): World, - singleDatabaseQuery: World, - multipleDatabaseQueries(total:Int!): [World], - getAllWorlds: [World], - helloWorld: String, - getAllFortunes: [Fortune], - getRandomAndUpdate(total:Int!): [World] - } - type Mutation { - createWorld: World!, - updateWorld(id:Int! randomNumber:String!): World! - } - type World { - id: Int!, - randomNumber: Int! - } - type Fortune { - id: Int! - message: String! - } -`; \ No newline at end of file diff --git a/frameworks/JavaScript/express/src/database/postgres.mjs b/frameworks/JavaScript/express/src/database/postgres.mjs index 5f22801d234..755f4133bfa 100644 --- a/frameworks/JavaScript/express/src/database/postgres.mjs +++ b/frameworks/JavaScript/express/src/database/postgres.mjs @@ -8,12 +8,14 @@ const sql = postgres({ max: 1, }); -export const fortunes = async () => await sql`SELECT id, message FROM fortune`; +export const fortunes = () => sql`SELECT id, message FROM fortune`; -export const find = async (id) => - await sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( - (arr) => arr[0] - ); +export const find = async (id) => { + const arr = await sql`SELECT id, randomNumber FROM world WHERE id = ${id}` + return arr[0] +}; + +export const getAllWorlds = () => sql`SELECT id, randomNumber FROM world` export const bulkUpdate = async (worlds) => { const sorted = sql( diff --git a/frameworks/JavaScript/express/src/server.mjs b/frameworks/JavaScript/express/src/server.mjs index 0de81c196cb..b723b200df1 100644 --- a/frameworks/JavaScript/express/src/server.mjs +++ b/frameworks/JavaScript/express/src/server.mjs @@ -1,105 +1,134 @@ import express from "express"; +import { LRUCache } from 'lru-cache'; import { generateRandomNumber, - getQueriesCount, - handleError, + parseQueries, escape, jsonSerializer, worldObjectSerializer, - sortByMessage, - writeResponse, - headerTypes, + worldsObjectSerializer, GREETING, + maxRows } from "./utils.mjs"; + let db; const { DATABASE } = process.env; if (DATABASE) db = await import(`./database/${DATABASE}.mjs`); -const extra = { id: 0, message: "Additional fortune added at request time." }; +const cache = new LRUCache({ + max: maxRows +}); + +const extra = () => ({ + id: 0, + message: "Additional fortune added at request time." +}); const app = express(); +app.set('x-powered-by', false); +app.set('etag', false); +app.set('case sensitive routing', true); +app.set('strict routing', true); + app.get("/plaintext", (req, res) => { - writeResponse(res, GREETING, headerTypes["plain"]); + res.writeHead(200, { + "content-type": "text/plain", + server: "Express", + }).end(GREETING); }); app.get("/json", (req, res) => { - writeResponse(res, jsonSerializer({ message: GREETING })); + res.writeHead(200, { + "content-type": "application/json", + server: "Express", + }).end(jsonSerializer({ message: GREETING })); }); if (db) { app.get("/db", async (req, res) => { - try { - const row = await db.find(generateRandomNumber()); - writeResponse(res, worldObjectSerializer(row)); - } catch (error) { - handleError(error, res); - } + const row = await db.find(generateRandomNumber()); + res.writeHead(200, { + "content-type": "application/json", + server: "Express", + }).end(worldObjectSerializer(row)); }); app.get("/queries", async (req, res) => { - try { - const queriesCount = getQueriesCount(req); - const databaseJobs = new Array(queriesCount) - .fill() - .map(() => db.find(generateRandomNumber())); - const worldObjects = await Promise.all(databaseJobs); - writeResponse(res, JSON.stringify(worldObjects)); - } catch (error) { - handleError(error, res); + const queries = parseQueries(req.query.queries); + const worldPromises = new Array(queries); + for (let i = 0; i < queries; i++) { + worldPromises[i] = db.find(generateRandomNumber()); } + const worlds = await Promise.all(worldPromises); + res.writeHead(200, { + "content-type": "application/json", + server: "Express", + }).end(worldsObjectSerializer(worlds)); }); app.get("/fortunes", async (req, res) => { - try { - const rows = [extra, ...(await db.fortunes())]; - sortByMessage(rows); - const n = rows.length; - let html = "", - i = 0; - for (; i < n; i++) { - html += `${rows[i].id}${escape( - rows[i].message - )}`; - } - - writeResponse( - res, - `Fortunes${html}
idmessage
`, - headerTypes["html"] - ); - } catch (error) { - handleError(error, res); + const rows = await db.fortunes(); + rows.push(extra()); + rows.sort((a, b) => (a.message < b.message) ? -1 : 1); + const n = rows.length; + let html = "", + i = 0; + for (; i < n; i++) { + const row = rows[i]; + html += `${row.id}${escape(row.message)}`; } + res.writeHead(200, { + "content-type": "text/html; charset=UTF-8", + server: "Express", + }).end(`Fortunes${html}
idmessage
`); }); app.get("/updates", async (req, res) => { - try { - const queriesCount = getQueriesCount(req); - const databaseJobs = new Array(queriesCount); - for (let i = 0; i < queriesCount; i++) { - databaseJobs[i] = db.find(generateRandomNumber()); - } - const worldObjects = await Promise.all(databaseJobs); + const queriesCount = parseQueries(req.query.queries); + const databaseJobs = new Array(queriesCount); + for (let i = 0; i < queriesCount; i++) { + databaseJobs[i] = db.find(generateRandomNumber()); + } + const worldObjects = await Promise.all(databaseJobs); - for (let i = 0; i < queriesCount; i++) { - worldObjects[i].randomNumber = generateRandomNumber(); + for (let i = 0; i < queriesCount; i++) { + worldObjects[i].randomNumber = generateRandomNumber(); + } + await db.bulkUpdate(worldObjects); + res.writeHead(200, { + "content-type": "application/json", + server: "Express", + }).end(worldsObjectSerializer(worldObjects)); + }); + + let isCachePopulated = false + app.get('/cached-worlds', async (req, res) => { + if (!isCachePopulated) { + const worlds = await db.getAllWorlds(); + for (let i = 0; i < worlds.length; i++) { + cache.set(worlds[i].id, worlds[i]); } - await db.bulkUpdate(worldObjects); - writeResponse(res, JSON.stringify(worldObjects)); - } catch (error) { - handleError(error, res); + isCachePopulated = true; } + const count = parseQueries(req.query.count); + const worlds = new Array(count); + + for (let i = 0; i < count; i++) { + worlds[i] = cache.get(generateRandomNumber()); + } + + res.writeHead(200, { + "content-type": "application/json", + server: "Express", + }).end(worldsObjectSerializer(worlds)); }); } -app.all("*", (req, res) => { - res.status(404).send("Not Found"); -}); - const host = process.env.HOST || "0.0.0.0"; const port = parseInt(process.env.PORT || "8080"); -app.listen(port, host, () => { +const server =app.listen(port, host, () => { console.log(`Server running at http://${host}:${port}/`); }); +server.keepAliveTimeout = 0; diff --git a/frameworks/JavaScript/express/src/utils.mjs b/frameworks/JavaScript/express/src/utils.mjs index 1acf96b0d51..3898314bd9e 100644 --- a/frameworks/JavaScript/express/src/utils.mjs +++ b/frameworks/JavaScript/express/src/utils.mjs @@ -1,32 +1,14 @@ -import { sjs, attr } from "slow-json-stringify"; +import fjs from 'fast-json-stringify'; export const GREETING = "Hello, World!"; -export const headerTypes = { - plain: "text/plain", - json: "application/json", - html: "text/html; charset=UTF-8", -}; - -export function writeResponse(res, text, type = headerTypes["json"]) { - res.writeHead(200, { - "content-type": type, - server: "Express", - }); - res.end(text); -} +export const maxQuery = 500 +export const maxRows = 10000 -export function handleError(error, response) { - console.error(error); - response.end("Internal Server Error"); -} - -export function getQueriesCount(request) { - return Math.min(parseInt(request.query["queries"]) || 1, 500); -} +export const parseQueries = (i) => i > maxQuery ? maxQuery : (i | 0) || 1; export function generateRandomNumber() { - return Math.ceil(Math.random() * 10000); + return ((Math.random() * maxRows) | 0) + 1; } const escapeHTMLRules = { @@ -42,27 +24,35 @@ const unsafeHTMLMatcher = /[&<>"'\/]/g; export function escape(text) { if (unsafeHTMLMatcher.test(text) === false) return text; - return text.replace(unsafeHTMLMatcher, function (m) { - return escapeHTMLRules[m] || m; - }); + return text.replace(unsafeHTMLMatcher, (m) => escapeHTMLRules[m] || m); } -export const jsonSerializer = sjs({ message: attr("string") }); -export const worldObjectSerializer = sjs({ - id: attr("number"), - randomnumber: attr("number"), +export const jsonSerializer = fjs({ + type: 'object', + properties: { + message: { + type: 'string', + format: 'unsafe', + } + } +}); + +export const worldObjectSerializer = fjs({ + type: 'object', + properties: { + id: { type: 'integer' }, + randomnumber: { type: 'integer' } + } }); -export function sortByMessage(arr) { - const n = arr.length; - for (let i = 1; i < n; i++) { - const c = arr[i]; - let j = i - 1; - while (j > -1 && c.message < arr[j].message) { - arr[j + 1] = arr[j]; - j--; +export const worldsObjectSerializer = fjs({ + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + randomnumber: { type: 'integer' } } - arr[j + 1] = c; } - return arr; -} +}); + diff --git a/frameworks/JavaScript/fastify/handlers.js b/frameworks/JavaScript/fastify/handlers.js index 5032b4b829d..66e11d0fcd2 100644 --- a/frameworks/JavaScript/fastify/handlers.js +++ b/frameworks/JavaScript/fastify/handlers.js @@ -27,7 +27,7 @@ module.exports = (databaseLayer) => ({ fortunes: async (req, reply) => { const fortunes = await databaseLayer.allFortunes(); - fortunes.push(h.additionalFortune); + fortunes.push(h.additionalFortune()); fortunes.sort(compare); return reply.view("/views/fortunes.hbs", { fortunes }); diff --git a/frameworks/JavaScript/fastify/helper.js b/frameworks/JavaScript/fastify/helper.js index 6369564b902..7feb524e656 100644 --- a/frameworks/JavaScript/fastify/helper.js +++ b/frameworks/JavaScript/fastify/helper.js @@ -5,8 +5,8 @@ module.exports = { return Math.min(Math.max(parseInt(queries) || 1, 1), 500); }, - additionalFortune: { + additionalFortune: () => ({ id: 0, message: "Additional fortune added at request time.", - }, + }), }; diff --git a/frameworks/JavaScript/hono/src/server.js b/frameworks/JavaScript/hono/src/server.js index 43364616d55..9fafd5cf2eb 100644 --- a/frameworks/JavaScript/hono/src/server.js +++ b/frameworks/JavaScript/hono/src/server.js @@ -26,7 +26,10 @@ app }); if (db) { - const extra = { id: 0, message: "Additional fortune added at request time." }; + const extra = () => ({ + id: 0, + message: "Additional fortune added at request time." + }); app .get("/db", async (c) => { @@ -49,7 +52,7 @@ if (db) { return c.json(worldObjects); }) .get("/fortunes", async (c) => { - const rows = [extra, ...(await db.fortunes())]; + const rows = [extra(), ...(await db.fortunes())]; sortByMessage(rows); diff --git a/frameworks/JavaScript/just/benchmark_config.json b/frameworks/JavaScript/just/benchmark_config.json index 3b195272644..373dbbc344c 100644 --- a/frameworks/JavaScript/just/benchmark_config.json +++ b/frameworks/JavaScript/just/benchmark_config.json @@ -25,7 +25,8 @@ "database_os": "Linux", "display_name": "just-js", "notes": "", - "versus": "" + "versus": "", + "tags": [ "broken" ] } } ] diff --git a/frameworks/JavaScript/koa/benchmark_config.json b/frameworks/JavaScript/koa/benchmark_config.json index 799fe45aa1f..943f4c66bd8 100644 --- a/frameworks/JavaScript/koa/benchmark_config.json +++ b/frameworks/JavaScript/koa/benchmark_config.json @@ -8,7 +8,6 @@ "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -50,7 +49,6 @@ "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -69,4 +67,4 @@ } } ] -} \ No newline at end of file +} diff --git a/frameworks/JavaScript/koa/handlers/handler.js b/frameworks/JavaScript/koa/handlers/handler.js index a6fbb8aa32c..4fa36224ebf 100644 --- a/frameworks/JavaScript/koa/handlers/handler.js +++ b/frameworks/JavaScript/koa/handlers/handler.js @@ -21,7 +21,7 @@ module.exports = (databaseLayer) => ({ Fortunes: async (ctx) => { const fortunes = await databaseLayer.allFortunes(); - fortunes.push(h.additionalFortune); + fortunes.push(h.additionalFortune()); fortunes.sort((a, b) => a.message.localeCompare(b.message)); return ctx.render('fortunes', {fortunes}); diff --git a/frameworks/JavaScript/koa/helper.js b/frameworks/JavaScript/koa/helper.js index d909c3a97c8..9c8fd97fe02 100644 --- a/frameworks/JavaScript/koa/helper.js +++ b/frameworks/JavaScript/koa/helper.js @@ -5,8 +5,8 @@ module.exports = { return Math.min(Math.max(parseInt(queries) || 1, 1), 500); }, - additionalFortune: { + additionalFortune: () => ({ id: 0, - message: 'Additional fortune added at request time.' - } + message: "Additional fortune added at request time.", + }) }; diff --git a/frameworks/JavaScript/koa/package.json b/frameworks/JavaScript/koa/package.json index 353a1d3990b..c22a6025990 100644 --- a/frameworks/JavaScript/koa/package.json +++ b/frameworks/JavaScript/koa/package.json @@ -15,6 +15,6 @@ "mysql2": "3.9.8", "pg": "8.5.1", "pg-hstore": "2.3.2", - "sequelize": "6.29.0" + "sequelize": "6.37.8" } } diff --git a/frameworks/JavaScript/mesh/benchmark_config.json b/frameworks/JavaScript/mesh/benchmark_config.json index bf91e85e86f..6f971304b3a 100644 --- a/frameworks/JavaScript/mesh/benchmark_config.json +++ b/frameworks/JavaScript/mesh/benchmark_config.json @@ -41,7 +41,8 @@ "database_os": "Linux", "display_name": "Mesh", "notes": "", - "versus": "nodejs" + "versus": "nodejs", + "tags": [ "broken" ] }, "postgres": { "dockerfile": "mesh-postgres.dockerfile", @@ -85,7 +86,8 @@ "database_os": "Linux", "display_name": "Mesh", "notes": "", - "versus": "nodejs" + "versus": "nodejs", + "tags": ["broken"] } } ] diff --git a/frameworks/JavaScript/nodejs/package.json b/frameworks/JavaScript/nodejs/package.json index 28dc35a011c..968c63faf7e 100644 --- a/frameworks/JavaScript/nodejs/package.json +++ b/frameworks/JavaScript/nodejs/package.json @@ -14,7 +14,7 @@ "pg-hstore": "2.3.2", "postgres": "^3.4.3", "slow-json-stringify": "^2.0.1", - "sequelize": "6.29.0", + "sequelize": "6.37.8", "node-cache": "4.1.1" }, "main": "app.js" diff --git a/frameworks/JavaScript/ringojs/benchmark_config.json b/frameworks/JavaScript/ringojs/benchmark_config.json index 74dfb0f50fe..94162be8899 100644 --- a/frameworks/JavaScript/ringojs/benchmark_config.json +++ b/frameworks/JavaScript/ringojs/benchmark_config.json @@ -21,7 +21,8 @@ "database_os": "Linux", "display_name": "ringojs", "notes": "", - "versus": "" + "versus": "", + "tags": ["broken"] }, "convenient": { "json_url": "/json", @@ -44,7 +45,8 @@ "database_os": "Linux", "display_name": "ringojs-conv", "notes": "Convenient", - "versus": "ringojs" + "versus": "ringojs", + "tags": ["broken"] } }] } diff --git a/frameworks/JavaScript/sailsjs/package.json b/frameworks/JavaScript/sailsjs/package.json index b2886f07639..1eb3b17ef67 100644 --- a/frameworks/JavaScript/sailsjs/package.json +++ b/frameworks/JavaScript/sailsjs/package.json @@ -16,7 +16,7 @@ "rc": "1.1.6", "sails": "1.5.7", "sails-disk": "0.10.10", - "sequelize": "6.29.0" + "sequelize": "6.37.8" }, "scripts": { "start": "node app.js", diff --git a/frameworks/JavaScript/spliffy/benchmark_config.json b/frameworks/JavaScript/spliffy/benchmark_config.json index 40dcb1614bd..3ce95240565 100644 --- a/frameworks/JavaScript/spliffy/benchmark_config.json +++ b/frameworks/JavaScript/spliffy/benchmark_config.json @@ -19,7 +19,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", - "tags": ["broken"], + "tags": [], "versus": "nodejs" }, "mongodb": { @@ -42,7 +42,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", - "tags": ["broken"], + "tags": [], "versus": "nodejs" }, "mysql": { @@ -65,7 +65,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", - "tags": ["broken"], + "tags": [], "versus": "nodejs" }, "postgres": { @@ -88,9 +88,9 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", - "tags": ["broken"], + "tags": [], "versus": "nodejs" } } ] -} +} \ No newline at end of file diff --git a/frameworks/JavaScript/spliffy/db/mysql.js b/frameworks/JavaScript/spliffy/db/mysql.js index 495dd50fab7..0ee9f7fd084 100644 --- a/frameworks/JavaScript/spliffy/db/mysql.js +++ b/frameworks/JavaScript/spliffy/db/mysql.js @@ -34,7 +34,7 @@ module.exports = { bulkUpdateWorld: async worlds => Promise.all( worlds.map( world => - execute( 'UPDATE world SET randomnumber = ? WHERE id = ?', - [world.randomnumber, world.id] ) ) + execute( 'UPDATE world SET randomNumber = ? WHERE id = ?', + [world.randomNumber, world.id] ) ) ).then( () => worlds ) } diff --git a/frameworks/JavaScript/spliffy/db/postgres.js b/frameworks/JavaScript/spliffy/db/postgres.js index 5dda948f150..2cfac8456db 100644 --- a/frameworks/JavaScript/spliffy/db/postgres.js +++ b/frameworks/JavaScript/spliffy/db/postgres.js @@ -1,44 +1,29 @@ -const { Client, Pool } = require( 'pg' ).native; -const cpus = require( 'os' ).cpus().length +const postgres = require('postgres'); -let clientOpts = { - host: process.env.DB_HOST || 'localhost', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass', - database: 'hello_world' -}; - -let pool - -const query = async ( text, values ) => ( await pool.query( text, values || undefined ) ).rows; +let sql; module.exports = { async init() { - const client = new Client( clientOpts ) - await client.connect() - const res = await client.query( 'SHOW max_connections' ) - let maxConnections = Math.floor( res.rows[0].max_connections * 0.9 / cpus ) - //1 worker per cpu, each worker pool gets a fraction of the max connections - //only use 90% to avoid too many clients errors - pool = new Pool( Object.assign( { ...clientOpts }, { max: maxConnections } ) ) - pool.on( 'error', ( err ) => { - console.error( 'Unexpected client error', err ) - } ) - await client.end() + sql = postgres({ + host: process.env.DB_HOST || 'tfb-database', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass', + database: 'hello_world', + fetch_types: false, + max: 1 + }); }, - allFortunes: async () => - query( 'SELECT * FROM fortune' ), + allFortunes: async () => await sql`SELECT id, message FROM fortune`, - worldById: async ( id ) => - query( 'SELECT * FROM world WHERE id = $1', [id] ) - .then( arr => arr[0] ), + worldById: async (id) => await sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then((arr) => arr[0]), - allWorlds: async () => - query( 'SELECT * FROM world' ), + allWorlds: async () => await sql`SELECT id, randomNumber FROM world`, - bulkUpdateWorld: async worlds => Promise.all( - worlds.map( world => - query( 'UPDATE world SET randomnumber = $1 WHERE id = $2', - [world.randomnumber, world.id] ) ) - ).then( () => worlds ) -} + bulkUpdateWorld: async (worlds) => { + const sortedWorlds = [...worlds].sort((a, b) => a.id - b.id); + await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sql(sortedWorlds.map(w => [w.id, w.randomNumber]))}) AS update_data (id, randomNumber) + WHERE world.id = (update_data.id)::int`; + return worlds; + } +} \ No newline at end of file diff --git a/frameworks/JavaScript/spliffy/fn.js b/frameworks/JavaScript/spliffy/fn.js index edf9f51dffe..cbf87a5499a 100644 --- a/frameworks/JavaScript/spliffy/fn.js +++ b/frameworks/JavaScript/spliffy/fn.js @@ -1,23 +1,29 @@ -module.exports = { - parseCount: ( i ) => Math.min( Math.max( parseInt( i, 10 ) || 1, 1 ), 500 ), - randomId: () => Math.floor( Math.random() * 10000 ) + 1, - randomUniqueIds: ( count ) => { - const used = new Map() - const ids = [] - for( let i = 0; i < count; i++ ) { - let id = module.exports.randomId() - if( used.has(id) ) { - for( let j = 0; j < 10000 - 1; j++ ) { - if( !used.has(id) ) break - id++ - if( id > 10000 ) { - id = 1 - } +const parseCount = ( i ) => Math.min( Math.max( parseInt( i, 10 ) || 1, 1 ), 500 ); + +const randomId = function() { return Math.floor( Math.random() * 10000 ) + 1; }; + +const randomUniqueIds = ( count ) => { + const used = new Map(); + const ids = []; + for( let i = 0; i < count; i++ ) { + let id = randomId(); // Use the locally defined randomId + if( used.has(id) ) { + for( let j = 0; j < 10000 - 1; j++ ) { + if( !used.has(id) ) break; + id++; + if( id > 10000 ) { + id = 1; } } - used.set(id, true) - ids.push(id) } - return ids - }, -} + used.set(id, true); + ids.push(id); + } + return ids; +}; + +module.exports = { + parseCount, + randomId, + randomUniqueIds +}; diff --git a/frameworks/JavaScript/spliffy/package-lock.json b/frameworks/JavaScript/spliffy/package-lock.json index 114cddc45d1..3bb7c9d2ef0 100644 --- a/frameworks/JavaScript/spliffy/package-lock.json +++ b/frameworks/JavaScript/spliffy/package-lock.json @@ -1,2821 +1,2010 @@ { "name": "spliffy-benchmark", - "version": "1.0.0", - "lockfileVersion": 1, + "version": "1.4.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@aws-sdk/client-sso-oidc": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", - "requires": { + "packages": { + "": { + "name": "spliffy-benchmark", + "version": "1.4.0", + "dependencies": { + "@srfnstack/spliffy": "1.4.0", + "html-escaper": "3.0.3", + "mongodb": "^4.17.0", + "mysql2": "^3.9.8", + "node-cache": "5.1.2", + "postgres": "3.4.4", + "slow-json-stringify": "^2.0.1" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.981.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.981.0.tgz", + "integrity": "sha512-Epc/dSH5VlAHBYxLGNZm+ZZNF2vHoNJdrVa1NJfYylaLVGgQpscoT8QN7ijqQUl7b888JAAGY5tAFSlvPqeoLA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "requires": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "requires": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - } - } - } - }, - "@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "requires": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - } - }, - "@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "requires": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "requires": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - } - } - } - }, - "@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", - "requires": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", - "requires": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "requires": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "requires": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-user-agent": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", - "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/util-user-agent-browser": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", - "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/util-user-agent-node": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", - "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/config-resolver": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", - "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/credential-provider-imds": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", - "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/hash-node": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", - "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "@smithy/invalid-dependency": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", - "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-content-length": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", - "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "requires": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-retry": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", - "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - } - }, - "@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "requires": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/service-error-classification": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", - "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", - "requires": { - "@smithy/types": "^3.3.0" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/smithy-client": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", - "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", - "requires": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "requires": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "requires": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-defaults-mode-browser": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", - "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-defaults-mode-node": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", - "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", - "requires": { - "@smithy/config-resolver": "^3.0.5", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", - "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", - "requires": { - "@smithy/service-error-classification": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "requires": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" - } + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/credential-provider-node": "^3.972.4", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.981.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" } }, - "@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", - "requires": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "requires": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "requires": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/signature-v4": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", - "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/smithy-client": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", - "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", - "requires": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "requires": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "requires": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "requires": { - "strnum": "^1.0.5" - } - } + "node_modules/@aws-sdk/client-sso": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.980.0.tgz", + "integrity": "sha512-AhNXQaJ46C1I+lQ+6Kj+L24il5K9lqqIanJd8lMszPmP7bLnmX0wTKK0dxywcvrLdij3zhWttjAKEBNgLtS8/A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.973.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.5.tgz", + "integrity": "sha512-IMM7xGfLGW6lMvubsA4j6BHU5FPgGAxoQ/NA63KqNLMwTS+PeMBcx8DPHL12Vg6yqOZnqok9Mu4H2BdQyq7gSA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/xml-builder": "^3.972.2", + "@smithy/core": "^3.22.0", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/signature-v4": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.3.tgz", + "integrity": "sha512-dW/DqTk90XW7hIngqntAVtJJyrkS51wcLhGz39lOMe0TlSmZl+5R/UGnAZqNbXmWuJHLzxe+MLgagxH41aTsAQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.980.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.980.0.tgz", + "integrity": "sha512-nLgMW2drTzv+dTo3ORCcotQPcrUaTQ+xoaDTdSaUXdZO7zbbVyk7ysE5GDTnJdZWcUjHOSB8xfNQhOTTNVPhFw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/credential-provider-node": "^3.972.4", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.3.tgz", + "integrity": "sha512-OBYNY4xQPq7Rx+oOhtyuyO0AQvdJSpXRg7JuPNBJH4a1XXIzJQl4UHQTPKZKwfJXmYLpv4+OkcFen4LYmDPd3g==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.5.tgz", + "integrity": "sha512-GpvBgEmSZPvlDekd26Zi+XsI27Qz7y0utUx0g2fSTSiDzhnd1FSa1owuodxR0BcUKNL7U2cOVhhDxgZ4iSoPVg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/types": "^3.973.1", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/util-stream": "^4.5.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.3.tgz", + "integrity": "sha512-rMQAIxstP7cLgYfsRGrGOlpyMl0l8JL2mcke3dsIPLWke05zKOFyR7yoJzWCsI/QiIxjRbxpvPiAeKEA6CoYkg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/credential-provider-env": "^3.972.3", + "@aws-sdk/credential-provider-http": "^3.972.5", + "@aws-sdk/credential-provider-login": "^3.972.3", + "@aws-sdk/credential-provider-process": "^3.972.3", + "@aws-sdk/credential-provider-sso": "^3.972.3", + "@aws-sdk/credential-provider-web-identity": "^3.972.3", + "@aws-sdk/nested-clients": "3.980.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/credential-provider-imds": "^4.2.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/nested-clients": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.980.0.tgz", + "integrity": "sha512-/dONY5xc5/CCKzOqHZCTidtAR4lJXWkGefXvTRKdSKMGaYbbKsxDckisd6GfnvPSLxWtvQzwgRGRutMRoYUApQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.3.tgz", + "integrity": "sha512-Gc3O91iVvA47kp2CLIXOwuo5ffo1cIpmmyIewcYjAcvurdFHQ8YdcBe1KHidnbbBO4/ZtywGBACsAX5vr3UdoA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/nested-clients": "3.980.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/nested-clients": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.980.0.tgz", + "integrity": "sha512-/dONY5xc5/CCKzOqHZCTidtAR4lJXWkGefXvTRKdSKMGaYbbKsxDckisd6GfnvPSLxWtvQzwgRGRutMRoYUApQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.4.tgz", + "integrity": "sha512-UwerdzosMSY7V5oIZm3NsMDZPv2aSVzSkZxYxIOWHBeKTZlUqW7XpHtJMZ4PZpJ+HMRhgP+MDGQx4THndgqJfQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.3", + "@aws-sdk/credential-provider-http": "^3.972.5", + "@aws-sdk/credential-provider-ini": "^3.972.3", + "@aws-sdk/credential-provider-process": "^3.972.3", + "@aws-sdk/credential-provider-sso": "^3.972.3", + "@aws-sdk/credential-provider-web-identity": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@smithy/credential-provider-imds": "^4.2.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.3.tgz", + "integrity": "sha512-xkSY7zjRqeVc6TXK2xr3z1bTLm0wD8cj3lAkproRGaO4Ku7dPlKy843YKnHrUOUzOnMezdZ4xtmFc0eKIDTo2w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.3.tgz", + "integrity": "sha512-8Ww3F5Ngk8dZ6JPL/V5LhCU1BwMfQd3tLdoEuzaewX8FdnT633tPr+KTHySz9FK7fFPcz5qG3R5edVEhWQD4AA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.980.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/token-providers": "3.980.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.3.tgz", + "integrity": "sha512-62VufdcH5rRfiRKZRcf1wVbbt/1jAntMj1+J0qAd+r5pQRg2t0/P9/Rz16B1o5/0Se9lVL506LRjrhIJAhYBfA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/nested-clients": "3.980.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/nested-clients": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.980.0.tgz", + "integrity": "sha512-/dONY5xc5/CCKzOqHZCTidtAR4lJXWkGefXvTRKdSKMGaYbbKsxDckisd6GfnvPSLxWtvQzwgRGRutMRoYUApQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.981.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.981.0.tgz", + "integrity": "sha512-ULmXLUvZqQDqH4SgTcFXHHUf9RSa/4H+BC3/UDpiq2t2515MUPqSw6cgEpCax/6v0zY5CVWe8GBGj/Rx/saGPA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.981.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/credential-provider-cognito-identity": "^3.972.3", + "@aws-sdk/credential-provider-env": "^3.972.3", + "@aws-sdk/credential-provider-http": "^3.972.5", + "@aws-sdk/credential-provider-ini": "^3.972.3", + "@aws-sdk/credential-provider-login": "^3.972.3", + "@aws-sdk/credential-provider-node": "^3.972.4", + "@aws-sdk/credential-provider-process": "^3.972.3", + "@aws-sdk/credential-provider-sso": "^3.972.3", + "@aws-sdk/credential-provider-web-identity": "^3.972.3", + "@aws-sdk/nested-clients": "3.981.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/credential-provider-imds": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.3.tgz", + "integrity": "sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.3.tgz", + "integrity": "sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.3.tgz", + "integrity": "sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.972.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.5.tgz", + "integrity": "sha512-TVZQ6PWPwQbahUI8V+Er+gS41ctIawcI/uMNmQtQ7RMcg3JYn6gyKAFKUb3HFYx2OjYlx1u11sETSwwEUxVHTg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@smithy/core": "^3.22.0", + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.981.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.981.0.tgz", + "integrity": "sha512-U8Nv/x0+9YleQ0yXHy0bVxjROSXXLzFzInRs/Q/Un+7FShHnS72clIuDZphK0afesszyDFS7YW4QFnm1sFIrCg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.981.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.3.tgz", + "integrity": "sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/config-resolver": "^4.4.6", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.980.0.tgz", + "integrity": "sha512-1nFileg1wAgDmieRoj9dOawgr2hhlh7xdvcH57b1NnqfPaVlcqVJyPc6k3TLDUFPY69eEwNxdGue/0wIz58vjA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/nested-clients": "3.980.0", + "@aws-sdk/types": "^3.973.1", + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.980.0.tgz", + "integrity": "sha512-/dONY5xc5/CCKzOqHZCTidtAR4lJXWkGefXvTRKdSKMGaYbbKsxDckisd6GfnvPSLxWtvQzwgRGRutMRoYUApQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.5", + "@aws-sdk/middleware-host-header": "^3.972.3", + "@aws-sdk/middleware-logger": "^3.972.3", + "@aws-sdk/middleware-recursion-detection": "^3.972.3", + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/region-config-resolver": "^3.972.3", + "@aws-sdk/types": "^3.973.1", + "@aws-sdk/util-endpoints": "3.980.0", + "@aws-sdk/util-user-agent-browser": "^3.972.3", + "@aws-sdk/util-user-agent-node": "^3.972.3", + "@smithy/config-resolver": "^4.4.6", + "@smithy/core": "^3.22.0", + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/hash-node": "^4.2.8", + "@smithy/invalid-dependency": "^4.2.8", + "@smithy/middleware-content-length": "^4.2.8", + "@smithy/middleware-endpoint": "^4.4.12", + "@smithy/middleware-retry": "^4.4.29", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/node-http-handler": "^4.4.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/smithy-client": "^4.11.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.28", + "@smithy/util-defaults-mode-node": "^4.2.31", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/util-endpoints": { + "version": "3.980.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", + "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.973.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.1.tgz", + "integrity": "sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.981.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.981.0.tgz", + "integrity": "sha512-a8nXh/H3/4j+sxhZk+N3acSDlgwTVSZbX9i55dx41gI1H+geuonuRG+Shv3GZsCb46vzc08RK2qC78ypO8uRlg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-endpoints": "^3.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.4.tgz", + "integrity": "sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.3.tgz", + "integrity": "sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.973.1", + "@smithy/types": "^4.12.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.972.3.tgz", + "integrity": "sha512-gqG+02/lXQtO0j3US6EVnxtwwoXQC5l2qkhLCrqUrqdtcQxV7FDMbm9wLjKqoronSHyELGTjbFKK/xV5q1bZNA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-user-agent": "^3.972.5", + "@aws-sdk/types": "^3.973.1", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.5.tgz", + "integrity": "sha512-mCae5Ys6Qm1LDu0qdGwx2UQ63ONUe+FHw908fJzLDqFKTDBK4LDZUqKWm4OkTCNFq19bftjsBSESIGLD/s3/rA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "fast-xml-parser": "5.3.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.3.tgz", + "integrity": "sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.8.tgz", + "integrity": "sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.6.tgz", + "integrity": "sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.3.8", + "@smithy/types": "^4.12.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-endpoints": "^3.2.8", + "@smithy/util-middleware": "^4.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.22.1.tgz", + "integrity": "sha512-x3ie6Crr58MWrm4viHqqy2Du2rHYZjwu8BekasrQx4ca+Y24dzVAwq3yErdqIbc2G3I0kLQA13PQ+/rde+u65g==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/middleware-serde": "^4.2.9", + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-stream": "^4.5.11", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.8.tgz", + "integrity": "sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.3.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.9.tgz", + "integrity": "sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^5.3.8", + "@smithy/querystring-builder": "^4.2.8", + "@smithy/types": "^4.12.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.8.tgz", + "integrity": "sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.8.tgz", + "integrity": "sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.8.tgz", + "integrity": "sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.13.tgz", + "integrity": "sha512-x6vn0PjYmGdNuKh/juUJJewZh7MoQ46jYaJ2mvekF4EesMuFfrl4LaW/k97Zjf8PTCPQmPgMvwewg7eNoH9n5w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/core": "^3.22.1", + "@smithy/middleware-serde": "^4.2.9", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "@smithy/url-parser": "^4.2.8", + "@smithy/util-middleware": "^4.2.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.4.30", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.30.tgz", + "integrity": "sha512-CBGyFvN0f8hlnqKH/jckRDz78Snrp345+PVk8Ux7pnkUCW97Iinse59lY78hBt04h1GZ6hjBN94BRwZy1xC8Bg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.3.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/service-error-classification": "^4.2.8", + "@smithy/smithy-client": "^4.11.2", + "@smithy/types": "^4.12.0", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-retry": "^4.2.8", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.9.tgz", + "integrity": "sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.8.tgz", + "integrity": "sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.8.tgz", + "integrity": "sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^4.2.8", + "@smithy/shared-ini-file-loader": "^4.4.3", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.9.tgz", + "integrity": "sha512-KX5Wml5mF+luxm1szW4QDz32e3NObgJ4Fyw+irhph4I/2geXwUy4jkIMUs5ZPGflRBeR6BUkC2wqIab4Llgm3w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/abort-controller": "^4.2.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/querystring-builder": "^4.2.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.8.tgz", + "integrity": "sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.8.tgz", + "integrity": "sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.8.tgz", + "integrity": "sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.8.tgz", + "integrity": "sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.8.tgz", + "integrity": "sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.3.tgz", + "integrity": "sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.8.tgz", + "integrity": "sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.8", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.11.2.tgz", + "integrity": "sha512-SCkGmFak/xC1n7hKRsUr6wOnBTJ3L22Qd4e8H1fQIuKTAjntwgU8lrdMe7uHdiT2mJAOWA/60qaW9tiMu69n1A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/core": "^3.22.1", + "@smithy/middleware-endpoint": "^4.4.13", + "@smithy/middleware-stack": "^4.2.8", + "@smithy/protocol-http": "^5.3.8", + "@smithy/types": "^4.12.0", + "@smithy/util-stream": "^4.5.11", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.12.0.tgz", + "integrity": "sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.8.tgz", + "integrity": "sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/querystring-parser": "^4.2.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", + "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", + "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "dependencies": { - "@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "requires": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "requires": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/smithy-client": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", - "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", - "requires": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "requires": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "requires": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - } - } + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.29", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.29.tgz", + "integrity": "sha512-nIGy3DNRmOjaYaaKcQDzmWsro9uxlaqUOhZDHQed9MW/GmkBZPtnU70Pu1+GT9IBmUXwRdDuiyaeiy9Xtpn3+Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^4.2.8", + "@smithy/smithy-client": "^4.11.2", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@aws-sdk/credential-providers": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.621.0.tgz", - "integrity": "sha512-FQbC7I8ae/72ZekLBa45jWJ+Q3d+YPhc3bW/rCks6RrldM6RgLTGr8pTOPCxHl828ky10RjkBiBmVU818rliyw==", - "requires": { - "@aws-sdk/client-cognito-identity": "3.621.0", - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/credential-provider-cognito-identity": "3.621.0", - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "requires": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "requires": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - } - } - } - }, - "@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "requires": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - } - }, - "@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "requires": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "requires": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - } - } - } - }, - "@aws-sdk/client-cognito-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.621.0.tgz", - "integrity": "sha512-FpXia5qFf6ijcNDWenVq+mP9r1LbiW/+52i9wrv2+Afi6Nn1ROf8W7St8WvE9TEZ3t78y+vis4CwqfGts+uiKA==", - "requires": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", - "requires": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/client-sts": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", - "requires": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-cognito-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.621.0.tgz", - "integrity": "sha512-Q+3awvTVJSqIGRjCUQflRwKPKlZ0TfmL3EQHgFLhZZrToeBapEA62+FY+T70aTKAZZZZprlvYeFPtBloNd5ziA==", - "requires": { - "@aws-sdk/client-cognito-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", - "requires": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "requires": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "requires": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/middleware-user-agent": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", - "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/util-user-agent-browser": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", - "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "@aws-sdk/util-user-agent-node": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", - "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/config-resolver": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", - "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/credential-provider-imds": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", - "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/hash-node": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", - "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "@smithy/invalid-dependency": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", - "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-content-length": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", - "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "requires": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-retry": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", - "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - } - }, - "@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "requires": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/service-error-classification": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", - "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", - "requires": { - "@smithy/types": "^3.3.0" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/smithy-client": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", - "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", - "requires": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "requires": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "requires": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-defaults-mode-browser": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", - "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-defaults-mode-node": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", - "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", - "requires": { - "@smithy/config-resolver": "^3.0.5", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", - "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", - "requires": { - "@smithy/service-error-classification": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "requires": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - } - } - }, - "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" - } + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.32", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.32.tgz", + "integrity": "sha512-7dtFff6pu5fsjqrVve0YMhrnzJtccCWDacNKOkiZjJ++fmjGExmmSu341x+WU6Oc1IccL7lDuaUj7SfrHpWc5Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/config-resolver": "^4.4.6", + "@smithy/credential-provider-imds": "^4.2.8", + "@smithy/node-config-provider": "^4.3.8", + "@smithy/property-provider": "^4.2.8", + "@smithy/smithy-client": "^4.11.2", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@aws-sdk/region-config-resolver": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", - "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", - "requires": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", + "node_modules/@smithy/util-endpoints": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.8.tgz", + "integrity": "sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^4.3.8", + "@smithy/types": "^4.12.0", "tslib": "^2.6.2" }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", + "license": "Apache-2.0", + "optional": true, "dependencies": { - "@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - } + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@aws-sdk/util-locate-window": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", - "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", - "requires": { - "tslib": "^2.5.0" + "node_modules/@smithy/util-middleware": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.8.tgz", + "integrity": "sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "node_modules/@smithy/util-retry": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.8.tgz", + "integrity": "sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==", + "license": "Apache-2.0", "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" + "dependencies": { + "@smithy/service-error-classification": "^4.2.8", + "@smithy/types": "^4.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@smithy/core": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", - "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", - "requires": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "dependencies": { - "@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "requires": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "requires": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-retry": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", - "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - } - }, - "@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "requires": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "requires": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/service-error-classification": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", - "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", - "requires": { - "@smithy/types": "^3.3.0" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/smithy-client": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", - "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", - "requires": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "requires": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "requires": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", - "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", - "requires": { - "@smithy/service-error-classification": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "requires": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "requires": { - "tslib": "^2.6.2" - } - }, - "@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "requires": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" - } + "node_modules/@smithy/util-stream": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.11.tgz", + "integrity": "sha512-lKmZ0S/3Qj2OF5H1+VzvDLb6kRxGzZHq6f3rAsoSu5cTLGsn3v3VQBA8czkNNXlLjoFEtVu3OQT2jEeOtOE2CA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.9", + "@smithy/node-http-handler": "^4.4.9", + "@smithy/types": "^4.12.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@smithy/util-endpoints": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", - "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", - "requires": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", + "node_modules/@smithy/util-utf8": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", + "license": "Apache-2.0", + "optional": true, "dependencies": { - "@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "requires": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "requires": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "requires": { - "tslib": "^2.6.2" - } - } + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "@srfnstack/spliffy": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@srfnstack/spliffy/-/spliffy-0.6.1.tgz", - "integrity": "sha512-uXqHMt8hHMZmkp+Ve9ou5pvTrTZOI270G50cgVDxha5rXu9Eki+7TvPvO20p7jM7lxG0BkYoEHxQhrD+kNMXbw==", - "requires": { - "cookie": "^0.4.0", + "node_modules/@srfnstack/spliffy": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@srfnstack/spliffy/-/spliffy-1.4.0.tgz", + "integrity": "sha512-MiZwoYXsYWMDkvMeqVZnkw6nmjK7kPsjOOaLpqfATrMFSeloj0iFvAoW8nAsZolk2m1ca6Nbg93dTVen3V+CXQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.2", "etag": "^1.8.1", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v19.3.0", - "uuid": "^3.3.3" + "uuid": "^11.1.0", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.56.0" + }, + "engines": { + "node": ">=20 <=24" } }, - "@types/node": { + "node_modules/@types/node": { "version": "20.5.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==" }, - "@types/webidl-conversions": { + "node_modules/@types/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" }, - "@types/whatwg-url": { + "node_modules/@types/whatwg-url": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "requires": { + "dependencies": { "@types/node": "*", "@types/webidl-conversions": "*" } }, - "base64-js": { + "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + "node_modules/bowser": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", + "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", + "license": "MIT", + "optional": true }, - "bson": { + "node_modules/bson": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", - "requires": { + "dependencies": { "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "buffer": { + "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, - "buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" - }, - "clone": { + "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" - }, - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "engines": { + "node": ">=0.8" + } }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "denque": { + "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } }, - "etag": { + "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "node_modules/fast-xml-parser": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz", + "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "strnum": "^2.1.2" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } }, - "generate-function": { + "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "requires": { + "dependencies": { "is-property": "^1.0.2" } }, - "html-escaper": { + "node_modules/html-escaper": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" }, - "iconv-lite": { + "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { + "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "ieee754": { + "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "ip": { + "node_modules/ip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, - "is-property": { + "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "libpq": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/libpq/-/libpq-1.8.12.tgz", - "integrity": "sha512-4lUY9BD9suz76mVS0kH4rRgRy620g/c9YZH5GYC3smfIpjtj6KiPuQ4IwQSHSZMMMhMM3tBFrYUrw8mHOOZVeg==", - "requires": { - "bindings": "1.5.0", - "nan": "^2.14.0" - } - }, - "long": { + "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, - "lru-cache": { + "node_modules/lru-cache": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", - "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==" + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", + "engines": { + "node": ">=16.14" + } }, - "memory-pager": { + "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "optional": true }, - "mongodb": { + "node_modules/mongodb": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.0.tgz", "integrity": "sha512-LZGMIPjPfWEfhPJATk1s9IvVTD18tyfKdT/0blCMih5vGagk2SwA9wFAUPMdtJpTrhXmyfGgwAaMkvneX2bn2A==", - "requires": { - "@aws-sdk/credential-providers": "^3.186.0", - "@mongodb-js/saslprep": "^1.1.0", + "dependencies": { "bson": "^4.7.2", "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "@mongodb-js/saslprep": "^1.1.0" } }, - "mongodb-connection-string-url": { + "node_modules/mongodb-connection-string-url": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "requires": { + "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" } }, - "mysql2": { + "node_modules/mysql2": { "version": "3.9.8", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.8.tgz", "integrity": "sha512-+5JKNjPuks1FNMoy9TYpl77f+5frbTklz7eb3XDwbpsERRLEeXiW2PDEkakYF50UuKU2qwfGnyXpKYvukv8mGA==", - "requires": { + "dependencies": { "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", @@ -2824,287 +2013,185 @@ "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" } }, - "named-placeholders": { + "node_modules/named-placeholders": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", - "requires": { + "dependencies": { "lru-cache": "^7.14.1" }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" - } + "engines": { + "node": ">=12.0.0" } }, - "nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==" + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } }, - "node-cache": { + "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", - "requires": { + "dependencies": { "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" } }, - "packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, - "pg": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.6.0.tgz", - "integrity": "sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ==", - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.5.0", - "pg-pool": "^3.3.0", - "pg-protocol": "^1.5.0", - "pg-types": "^2.1.0", - "pgpass": "1.x" - } - }, - "pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" - }, - "pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-native": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pg-native/-/pg-native-3.0.1.tgz", - "integrity": "sha512-LBVNWkNh0fVx/cienARRP2y22J5OpUsKBe0TpxzAx3arEUUdIs77aLSAHS3scS7SMaqc+OkG40CEu5fN0/cjIw==", - "requires": { - "libpq": "^1.8.10", - "pg-types": "^1.12.1", - "readable-stream": "1.0.31" - }, - "dependencies": { - "pg-types": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz", - "integrity": "sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ==", - "requires": { - "pg-int8": "1.0.1", - "postgres-array": "~1.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.0", - "postgres-interval": "^1.1.0" - } - }, - "postgres-array": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.3.tgz", - "integrity": "sha512-5wClXrAP0+78mcsNX3/ithQ5exKvCyK5lr5NEEEeGwwM6NJdQgzIJBVxLvRW+huFpX92F2QnZ5CcokH0VhK2qQ==" - }, - "readable-stream": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", - "integrity": "sha512-tco/Dwv1f/sgIgN6CWdj/restacPKNskK6yps1981ivH2ZmLYcs5o5rVzL3qaO/cSkhN8hYOMWs7+glzOLSgRg==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" - } + "node_modules/postgres": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.4.tgz", + "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", + "license": "Unlicense", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" } }, - "pg-pool": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz", - "integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==" - }, - "pg-protocol": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", - "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" - }, - "pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "requires": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - } - }, - "pgpass": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", - "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", - "requires": { - "split2": "^3.1.1" - } - }, - "postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" - }, - "postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - }, - "postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "requires": { - "xtend": "^4.0.0" - } - }, - "punycode": { + "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "seq-queue": { + "node_modules/seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, - "smart-buffer": { + "node_modules/slow-json-stringify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/slow-json-stringify/-/slow-json-stringify-2.0.1.tgz", + "integrity": "sha512-jqyzIqTaSkRGcWdWqjmOLKHZgOGUT71ZCTsvQu1xGu9Mqaod7O26y5FJJEmaUQhaTWh0bkXv2qqN0i+EQsD1jQ==", + "license": "MIT" + }, + "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } }, - "socks": { + "node_modules/socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "requires": { + "dependencies": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" } }, - "sparse-bitfield": { + "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "optional": true, - "requires": { + "dependencies": { "memory-pager": "^1.0.2" } }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } - }, - "sqlstring": { + "node_modules/sqlstring": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" } }, - "strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + "node_modules/strnum": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", + "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "optional": true }, - "tr46": { + "node_modules/tr46": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "requires": { + "dependencies": { "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" } }, - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "uWebSockets.js": { - "version": "github:uNetworking/uWebSockets.js#7bf0faac5859fef2d113e83d22803f7833774c11", - "from": "github:uNetworking/uWebSockets.js#v19.3.0" + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "node_modules/uWebSockets.js": { + "version": "19.3.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#7bf0faac5859fef2d113e83d22803f7833774c11", + "integrity": "sha512-u7PYqVALGEo4O0yKEwmm2nhlS9XVtAx6/M814dpqjVuPBP2lkgExLtbz2XalW6lT6mXGzlBesYYjh82WRqhlcw==" }, - "webidl-conversions": { + "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } }, - "whatwg-url": { + "node_modules/whatwg-url": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "requires": { + "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" } } } diff --git a/frameworks/JavaScript/spliffy/package.json b/frameworks/JavaScript/spliffy/package.json index 62b2240acf3..7a769b2fd99 100644 --- a/frameworks/JavaScript/spliffy/package.json +++ b/frameworks/JavaScript/spliffy/package.json @@ -1,14 +1,14 @@ { "name": "spliffy-benchmark", - "version": "1.0.0", + "version": "1.4.0", "main": "start.js", "dependencies": { - "@srfnstack/spliffy": "0.6.1", + "@srfnstack/spliffy": "1.4.0", "html-escaper": "3.0.3", "mongodb": "^4.17.0", "mysql2": "^3.9.8", "node-cache": "5.1.2", - "pg": "8.6.0", - "pg-native": "3.0.1" + "postgres": "3.4.4", + "slow-json-stringify": "^2.0.1" } } diff --git a/frameworks/JavaScript/spliffy/spliffy-mongodb.dockerfile b/frameworks/JavaScript/spliffy/spliffy-mongodb.dockerfile index 6ad600fec50..c3fc25ba0a0 100644 --- a/frameworks/JavaScript/spliffy/spliffy-mongodb.dockerfile +++ b/frameworks/JavaScript/spliffy/spliffy-mongodb.dockerfile @@ -1,6 +1,6 @@ -FROM node:14-buster-slim +FROM node:24-trixie-slim -RUN apt update && apt install -y libpq-dev g++ make git python +RUN apt update && apt install -y libpq-dev g++ make git python3 COPY package.json /app/ WORKDIR /app RUN npm install diff --git a/frameworks/JavaScript/spliffy/spliffy-mysql.dockerfile b/frameworks/JavaScript/spliffy/spliffy-mysql.dockerfile index 0e1c66e2944..90ae2245f32 100644 --- a/frameworks/JavaScript/spliffy/spliffy-mysql.dockerfile +++ b/frameworks/JavaScript/spliffy/spliffy-mysql.dockerfile @@ -1,6 +1,6 @@ -FROM node:14-buster-slim +FROM node:24-trixie-slim -RUN apt update && apt install -y libpq-dev g++ make git python +RUN apt update && apt install -y libpq-dev g++ make git python3 COPY package.json /app/ WORKDIR /app RUN npm install diff --git a/frameworks/JavaScript/spliffy/spliffy-postgres.dockerfile b/frameworks/JavaScript/spliffy/spliffy-postgres.dockerfile index 2183a18b31e..99823203357 100644 --- a/frameworks/JavaScript/spliffy/spliffy-postgres.dockerfile +++ b/frameworks/JavaScript/spliffy/spliffy-postgres.dockerfile @@ -1,6 +1,6 @@ -FROM node:14-buster-slim +FROM node:24-trixie-slim -RUN apt update && apt install -y libpq-dev g++ make git python +RUN apt update && apt install -y libpq-dev g++ make git python3 COPY package.json /app/ WORKDIR /app RUN npm install diff --git a/frameworks/JavaScript/spliffy/spliffy.dockerfile b/frameworks/JavaScript/spliffy/spliffy.dockerfile index eeb7acd4be2..fc09e3cf672 100644 --- a/frameworks/JavaScript/spliffy/spliffy.dockerfile +++ b/frameworks/JavaScript/spliffy/spliffy.dockerfile @@ -1,6 +1,6 @@ -FROM node:14-buster-slim +FROM node:24-trixie-slim -RUN apt update && apt install -y libpq-dev g++ make git python +RUN apt update && apt install -y libpq-dev g++ make git python3 COPY package.json /app/ WORKDIR /app RUN npm install @@ -8,4 +8,4 @@ COPY . /app EXPOSE 1420 -CMD ["node", "/app/start.js"] +CMD ["node", "/app/start.js"] \ No newline at end of file diff --git a/frameworks/JavaScript/spliffy/start.js b/frameworks/JavaScript/spliffy/start.js index 98648158137..966eeaf224d 100644 --- a/frameworks/JavaScript/spliffy/start.js +++ b/frameworks/JavaScript/spliffy/start.js @@ -1,21 +1,26 @@ const cluster = require( 'cluster' ) -const cpus = require( 'os' ).cpus().length +const cpus = require( 'os' ).availableParallelism ? require( 'os' ).availableParallelism() : require( 'os' ).cpus().length const db = require( './db' ) -if( cluster.isMaster ) { +if( cluster.isPrimary || cluster.isMaster ) { for( let i = 0; i < cpus; i++ ) { cluster.fork(); } } else { + require('uWebSockets.js')._cfg('silent') db.init() - .then( () => { - require( '@srfnstack/spliffy' )( + .then( async () => { + const spliffy = (await import( '@srfnstack/spliffy' )).default + spliffy( { routeDir: __dirname + '/www', port: 1420, - logAccess: false + logAccess: false, + decodePathParameters: false, + parseCookie: false, + writeDateHeader: false } ) } ) -} +} \ No newline at end of file diff --git a/frameworks/JavaScript/spliffy/www/cached-worlds.rt.js b/frameworks/JavaScript/spliffy/www/cached-worlds.rt.js index 307e6fd1041..92c2d9bf0bf 100644 --- a/frameworks/JavaScript/spliffy/www/cached-worlds.rt.js +++ b/frameworks/JavaScript/spliffy/www/cached-worlds.rt.js @@ -1,13 +1,21 @@ +const { parseCount, randomUniqueIds } = require("../fn"); const NodeCache = require( 'node-cache' ) const worldCache = new NodeCache() -const db = require( '../db' ) -const { parseCount, randomUniqueIds } = require( '../fn' ) +const db = require('../db') if(db.allWorlds){ db.allWorlds().then( worlds => worlds.forEach( world => worldCache.set( world.id, world ) ) ) } - module.exports = { - GET: ( { url: { query: { count } } } ) => - randomUniqueIds( parseCount( count ) ) - .map(worldCache.get) + GET: async ({ url, res }) => { + const count = parseCount(url.query.count); + const ids = randomUniqueIds(count) + const results = []; + for (let i = 0; i < count; i++) { + results.push(worldCache.get(ids[i])); + } + const worlds = await Promise.all(results); + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'application/json'; + return JSON.stringify(worlds); + } } diff --git a/frameworks/JavaScript/spliffy/www/db.rt.js b/frameworks/JavaScript/spliffy/www/db.rt.js index 22a39370efd..d7d6227f62f 100644 --- a/frameworks/JavaScript/spliffy/www/db.rt.js +++ b/frameworks/JavaScript/spliffy/www/db.rt.js @@ -1,6 +1,23 @@ -const db = require( '../db' ) -const { randomId } = require( "../fn" ); +const db = require('../db') +const { randomId } = require("../fn"); +const { sjs, attr } = require('slow-json-stringify'); -module.exports = { - GET: () => db.worldById( randomId() ) +// Define serializers for different database casings, the verify tests fail without this +const mongoMysqlWorldObjectSerializer = sjs({ id: attr('number'), randomNumber: attr('number') }); +const postgresWorldObjectSerializer = sjs({ id: attr('number'), randomnumber: attr('number') }); +// Choose serializer based on the DATABASE environment variable +let serializer; +if (process.env.DATABASE === 'postgres') { + serializer = postgresWorldObjectSerializer; +} else { + // Default to camelCase for MongoDB and MySQL + serializer = mongoMysqlWorldObjectSerializer; } +module.exports = { + GET: async ({ res }) => { + const row = await db.worldById(randomId()); + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'application/json'; + return serializer(row); + } +}; diff --git a/frameworks/JavaScript/spliffy/www/fortunes.rt.js b/frameworks/JavaScript/spliffy/www/fortunes.rt.js index 3016128bf67..b9acbe3ac4f 100644 --- a/frameworks/JavaScript/spliffy/www/fortunes.rt.js +++ b/frameworks/JavaScript/spliffy/www/fortunes.rt.js @@ -1,30 +1,39 @@ -const db = require( '../db' ) -const { escape } = require( 'html-escaper' ) +const db = require('../db') +const { escape } = require('html-escaper') -const runTimeFortune = { +const runTimeFortune = () => ({ id: 0, message: 'Additional fortune added at request time.' -} +}) -const renderBody = fortunes => { - let body = 'Fortunes' - for( let fortune of fortunes ) { - body += `` +function sortByMessage(arr) { + const n = arr.length + for (let i = 1; i < n; i++) { + const c = arr[i] + let j = i - 1 + while ((j > -1) && (c.message < arr[j].message)) { + arr[j + 1] = arr[j] + j-- + } + arr[j + 1] = c } - body += '
idmessage
${fortune.id}${escape( fortune.message )}
' - return body + return arr } module.exports = { - GET: async () => { + GET: async ({ res }) => { let fortunes = await db.allFortunes() - fortunes.push( runTimeFortune ) - fortunes.sort( ( a, b ) => a.message.localeCompare( b.message ) ) - return { - headers: { - 'Content-Type': 'text/html; charset=utf-8' - }, - body: renderBody( fortunes ) + fortunes.push(runTimeFortune()) + sortByMessage(fortunes) + + let html = 'Fortunes'; + for (let i = 0; i < fortunes.length; i++) { + html += ``; } + html += '
idmessage
${fortunes[i].id}${escape(fortunes[i].message)}
'; + + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'text/html; charset=utf-8'; + return html; } } diff --git a/frameworks/JavaScript/spliffy/www/json.rt.js b/frameworks/JavaScript/spliffy/www/json.rt.js index 6b41ad33b46..219c8ff4d5d 100644 --- a/frameworks/JavaScript/spliffy/www/json.rt.js +++ b/frameworks/JavaScript/spliffy/www/json.rt.js @@ -1,3 +1,10 @@ +const { sjs, attr } = require('slow-json-stringify'); +const jsonSerializer = sjs({ message: attr("string")}); + module.exports = { - GET: () => ( { message: 'Hello, World!' } ) -} + GET: ({ res }) => { + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'application/json'; + return jsonSerializer({ message: 'Hello, World!' }); + } +} \ No newline at end of file diff --git a/frameworks/JavaScript/spliffy/www/plaintext.rt.js b/frameworks/JavaScript/spliffy/www/plaintext.rt.js index 47fd251e20c..f51e4d6430f 100644 --- a/frameworks/JavaScript/spliffy/www/plaintext.rt.js +++ b/frameworks/JavaScript/spliffy/www/plaintext.rt.js @@ -1,6 +1,7 @@ module.exports = { - GET: ( { res } ) => { - res.headers['content-type'] = 'text/plain' - return 'Hello, World!' + GET: ({ res }) => { + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'text/plain'; + return 'Hello, World!'; } } diff --git a/frameworks/JavaScript/spliffy/www/queries.rt.js b/frameworks/JavaScript/spliffy/www/queries.rt.js index 5a2ab8748f4..ac697cd856f 100644 --- a/frameworks/JavaScript/spliffy/www/queries.rt.js +++ b/frameworks/JavaScript/spliffy/www/queries.rt.js @@ -1,8 +1,17 @@ -const db = require( '../db' ) -const { parseCount, randomUniqueIds } = require( '../fn' ) +const db = require('../db') +const { parseCount, randomUniqueIds } = require("../fn"); + module.exports = { - GET: async ( { url: { query: { queries } } } ) => await Promise.all( - randomUniqueIds( parseCount( queries ) ) - .map( id => db.worldById( id ) ) - ) + GET: async ({ url, res }) => { + const count = parseCount(url.query.queries); + const ids = randomUniqueIds(count) + const results = []; + for (let i = 0; i < count; i++) { + results.push(db.worldById(ids[i])); + } + const worlds = await Promise.all(results); + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'application/json'; + return JSON.stringify(worlds); + } } diff --git a/frameworks/JavaScript/spliffy/www/updates.rt.js b/frameworks/JavaScript/spliffy/www/updates.rt.js index 5c7c2154c2e..38cac752a19 100644 --- a/frameworks/JavaScript/spliffy/www/updates.rt.js +++ b/frameworks/JavaScript/spliffy/www/updates.rt.js @@ -1,19 +1,25 @@ -const db = require( '../db' ) -const { randomId, randomUniqueIds, parseCount } = require( "../fn" ); - -randomNumber = process.env.DATABASE === 'mongodb' ? 'randomNumber' : 'randomnumber' +const db = require('../db') +const { parseCount, randomId } = require("../fn"); module.exports = { - GET: async ( { url: { query: { queries } } } ) => await db.bulkUpdateWorld( - await Promise.all( - randomUniqueIds( parseCount( queries ) ) - .map( id => - db.worldById( id ) - .then( world => { - world[randomNumber] = randomId() - return world - } ) - ) - ) - ) + GET: async ({ url, res }) => { + const count = parseCount(url.query.queries); + const results = []; + for (let i = 0; i < count; i++) { + results.push(db.worldById(randomId())); + } + const worlds = await Promise.all(results); + for (let i = 0; i < count; i++) { + worlds[i].randomNumber = randomId(); + } + res.headers['server'] = 'spliffy'; + res.headers['content-type'] = 'application/json'; + + if (worlds.length === 0) { + return JSON.stringify([]); + } + + await db.bulkUpdateWorld(worlds); + return JSON.stringify(worlds); + } } diff --git a/frameworks/JavaScript/ultimate-express/app.js b/frameworks/JavaScript/ultimate-express/app.js index 1914abf8d17..6eaeb723352 100755 --- a/frameworks/JavaScript/ultimate-express/app.js +++ b/frameworks/JavaScript/ultimate-express/app.js @@ -17,15 +17,34 @@ const jsonSerializer = fjs({ } }); -const generateRandomNumber = () => Math.floor(Math.random() * maxRows) + 1; +const worldSerializer = fjs({ + type: 'object', + properties: { + id: { type: 'integer' }, + randomnumber: { type: 'integer' } + } +}); + +const worldsSerializer = fjs({ + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'integer' }, + randomnumber: { type: 'integer' } + } + } +}); + +const generateRandomNumber = () => ((Math.random() * maxRows) | 0) + 1; -const parseQueries = (i) => Math.min(parseInt(i) || 1, maxQuery); +const parseQueries = (i) => i > maxQuery ? maxQuery : (i | 0) || 1; const escapeHTMLRules = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/' }; const unsafeHTMLMatcher = /[&<>"'\/]/g; -const escapeHTMLCode = (text) => unsafeHTMLMatcher.test(text) ? text.replace(unsafeHTMLMatcher, function (m) { return escapeHTMLRules[m] || m; }) : text; +const escapeHTMLCode = (text) => unsafeHTMLMatcher.test(text) ? text.replace(unsafeHTMLMatcher, m => escapeHTMLRules[m] || m) : text; const cache = new LRUCache({ max: maxRows @@ -50,105 +69,88 @@ app.get('/json', (req, res) => { if (db) { app.get('/db', async (req, res) => { res.setHeader('Server', 'UltimateExpress'); - - try { - const world = await db.find(generateRandomNumber()); - res.json(world); - } catch (error) { - throw error; - } + res.setHeader('Content-Type', 'application/json'); + const world = await db.find(generateRandomNumber()); + res.end(worldSerializer(world)); }); app.get('/queries', async (req, res) => { res.setHeader('Server', 'UltimateExpress'); + res.setHeader('Content-Type', 'application/json'); - try { - const queries = parseQueries(req.query.queries); - const worldPromises = new Array(queries); + const queries = parseQueries(req.query.queries); + const worldPromises = new Array(queries); - for (let i = 0; i < queries; i++) { - worldPromises[i] = db.find(generateRandomNumber()); - } + for (let i = 0; i < queries; i++) { + worldPromises[i] = db.find(generateRandomNumber()); + } - const worlds = await Promise.all(worldPromises); + const worlds = await Promise.all(worldPromises); - res.json(worlds); - } catch (error) { - throw error; - } + res.end(worldsSerializer(worlds)); }) app.get('/updates', async (req, res) => { res.setHeader('Server', 'UltimateExpress'); + res.setHeader('Content-Type', 'application/json'); - try { - const queries = parseQueries(req.query.queries); - const worldPromises = new Array(queries); + const queries = parseQueries(req.query.queries); + const worldPromises = new Array(queries); - for (let i = 0; i < queries; i++) { - worldPromises[i] = db.find(generateRandomNumber()); - } + for (let i = 0; i < queries; i++) { + worldPromises[i] = db.find(generateRandomNumber()); + } - const worlds = await Promise.all(worldPromises); + const worlds = await Promise.all(worldPromises); - for (let i = 0; i < queries; i++) { - worlds[i].randomNumber = generateRandomNumber(); - } + for (let i = 0; i < queries; i++) { + worlds[i].randomNumber = generateRandomNumber(); + } - await db.bulkUpdate(worlds); + await db.bulkUpdate(worlds); - res.json(worlds); - } catch (error) { - throw error; - } + res.end(worldsSerializer(worlds)); }) app.get('/fortunes', async (req, res) => { res.setHeader('Server', 'UltimateExpress'); - try { - const fortunes = await db.fortunes() + const fortunes = await db.fortunes() - fortunes.push({ id: 0, message: 'Additional fortune added at request time.' }); + fortunes.push({ id: 0, message: 'Additional fortune added at request time.' }); - fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); + fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); - const n = fortunes.length + const n = fortunes.length - let i = 0, html = '' - for (; i < n; i++) html += `${fortunes[i].id}${escapeHTMLCode(fortunes[i].message)}` + let i = 0, html = '' + for (; i < n; i++) html += `${fortunes[i].id}${escapeHTMLCode(fortunes[i].message)}` - res - .header('Content-Type', 'text/html; charset=utf-8') - .end(`Fortunes${html}
idmessage
`); - } catch (error) { - throw error; - } + res + .header('Content-Type', 'text/html; charset=utf-8') + .end(`Fortunes${html}
idmessage
`); }) let isCachePopulated = false app.get('/cached-worlds', async (req, res) => { res.setHeader('Server', 'UltimateExpress'); + res.setHeader('Content-Type', 'application/json'); - try { - if (!isCachePopulated) { - const worlds = await db.getAllWorlds(); - for (let i = 0; i < worlds.length; i++) { - cache.set(worlds[i].id, worlds[i]); - } - isCachePopulated = true; - } - const count = parseQueries(req.query.count); - const worlds = new Array(count); - - for (let i = 0; i < count; i++) { - worlds[i] = cache.get(generateRandomNumber()); + if (!isCachePopulated) { + const worlds = await db.getAllWorlds(); + for (let i = 0; i < worlds.length; i++) { + cache.set(worlds[i].id, worlds[i]); } + isCachePopulated = true; + } + const count = parseQueries(req.query.count); + const worlds = new Array(count); - res.json(worlds); - } catch (error) { - throw error; + for (let i = 0; i < count; i++) { + worlds[i] = cache.get(generateRandomNumber()); } + + res.end(worldsSerializer(worlds)); }); } diff --git a/frameworks/JavaScript/ultimate-express/database/mysql.js b/frameworks/JavaScript/ultimate-express/database/mysql.js index 5e7949997e7..ca45835631d 100644 --- a/frameworks/JavaScript/ultimate-express/database/mysql.js +++ b/frameworks/JavaScript/ultimate-express/database/mysql.js @@ -4,12 +4,13 @@ import { clientOpts } from '../config.js' const pool = createPool({ ...clientOpts, connectionLimit: cpus().length }) -const execute = (text, values) => pool.execute(text, values || undefined) +export const fortunes = () => pool.execute('SELECT id, message FROM fortune') -export const fortunes = () => execute('SELECT id, message FROM fortune') +export const find = async(id) => { + const arr = await pool.execute('SELECT id, randomNumber AS randomnumber FROM world WHERE id = ?', [id]); + return arr[0]; +} -export const find = (id) => execute('SELECT id, randomNumber FROM world WHERE id = ?', [id]).then(arr => arr[0]) - -export const getAllWorlds = () => execute('SELECT id, randomNumber FROM world') +export const getAllWorlds = () => pool.execute('SELECT id, randomNumber AS randomnumber FROM world') export const bulkUpdate = (worlds) => pool.batch('UPDATE world SET randomNumber = ? WHERE id = ?', worlds.map(world => [world.randomNumber, world.id]).sort((a, b) => (a[1] < b[1]) ? -1 : 1)) \ No newline at end of file diff --git a/frameworks/JavaScript/ultimate-express/database/postgres.js b/frameworks/JavaScript/ultimate-express/database/postgres.js index 5bfad8e13ad..6846da4d5fe 100644 --- a/frameworks/JavaScript/ultimate-express/database/postgres.js +++ b/frameworks/JavaScript/ultimate-express/database/postgres.js @@ -1,14 +1,17 @@ import postgres from 'postgres' import { clientOpts } from '../config.js' -const sql = postgres({ ...clientOpts, max: 1 }) +const sql = postgres({ ...clientOpts, max: 1, fetch_types: false }) -export const fortunes = async () => sql`SELECT id, message FROM fortune` +export const fortunes = () => sql`SELECT id, message FROM fortune` -export const find = async (id) => sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then((arr) => arr[0]) +export const find = async (id) => { + const res = await sql`SELECT id, randomNumber FROM world WHERE id = ${id}` + return res[0] +} -export const getAllWorlds = async () => sql`SELECT id, randomNumber FROM world` +export const getAllWorlds = () => sql`SELECT id, randomNumber FROM world` -export const bulkUpdate = async (worlds) => await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int +export const bulkUpdate = (worlds) => 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) WHERE world.id = (update_data.id)::int`; \ No newline at end of file diff --git a/frameworks/JavaScript/ultimate-express/package-lock.json b/frameworks/JavaScript/ultimate-express/package-lock.json index 682c187f205..bd0f0099bad 100644 --- a/frameworks/JavaScript/ultimate-express/package-lock.json +++ b/frameworks/JavaScript/ultimate-express/package-lock.json @@ -9,11 +9,11 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "fast-json-stringify": "^6.0.0", - "lru-cache": "^10.0.1", - "mariadb": "^3.2.0", - "postgres": "^3.3.5", - "ultimate-express": "^2.0.9" + "fast-json-stringify": "^6.2.0", + "lru-cache": "^11.2.4", + "mariadb": "^3.4.5", + "postgres": "^3.4.8", + "ultimate-express": "^2.0.15" } }, "node_modules/@fastify/merge-json-schemas": { @@ -164,9 +164,9 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -244,12 +244,16 @@ } }, "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cookie-signature": { @@ -354,9 +358,9 @@ "license": "MIT" }, "node_modules/fast-json-stringify": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.0.1.tgz", - "integrity": "sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.2.0.tgz", + "integrity": "sha512-Eaf/KNIDwHkzfyeQFNfLXJnQ7cl1XQI3+zRqmPlvtkMigbXnAcasTrvJQmquBSxKfFGeRA6PFog8t+hFmpDoWw==", "funding": [ { "type": "github", @@ -373,7 +377,7 @@ "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0", - "json-schema-ref-resolver": "^2.0.0", + "json-schema-ref-resolver": "^3.0.0", "rfdc": "^1.2.0" } }, @@ -534,9 +538,9 @@ } }, "node_modules/json-schema-ref-resolver": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-2.0.1.tgz", - "integrity": "sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz", + "integrity": "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==", "funding": [ { "type": "github", @@ -559,10 +563,13 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, "node_modules/mariadb": { "version": "3.4.5", @@ -580,6 +587,12 @@ "node": ">= 14" } }, + "node_modules/mariadb/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -647,9 +660,9 @@ } }, "node_modules/postgres": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", - "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.8.tgz", + "integrity": "sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==", "license": "Unlicense", "engines": { "node": ">=12" @@ -673,9 +686,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -840,16 +853,16 @@ } }, "node_modules/ultimate-express": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/ultimate-express/-/ultimate-express-2.0.9.tgz", - "integrity": "sha512-7Pw3iueUmS7603iq9b1pntYYhpvMdjtnvoe/VZEHEctU/TRZ/X1B48wGZaZklSYFoTy1SDDjsPz/Qfes1ADDJg==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/ultimate-express/-/ultimate-express-2.0.15.tgz", + "integrity": "sha512-f8xaMzBewdMbOL+7S2pCRaKBqmbkm8M7bb68heWN+lQe3ux8dKaHhandYiw9SFatO2mM/tgh5AZX1OmR7Gw2RA==", "license": "Apache-2.0", "dependencies": { "@types/express": "^4.17.21", "accepts": "^1.3.8", - "acorn": "^8.14.1", + "acorn": "^8.15.0", "bytes": "^3.1.2", - "cookie": "^1.0.2", + "cookie": "^1.1.1", "cookie-signature": "^1.2.2", "encodeurl": "^2.0.0", "etag": "^1.8.1", @@ -859,12 +872,12 @@ "mime-types": "^2.1.35", "ms": "^2.1.3", "proxy-addr": "^2.0.7", - "qs": "^6.14.0", + "qs": "^6.14.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1", + "statuses": "^2.0.2", "tseep": "^1.3.1", "type-is": "^2.0.1", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.52.0", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.56.0", "vary": "^1.1.2" }, "engines": { diff --git a/frameworks/JavaScript/ultimate-express/package.json b/frameworks/JavaScript/ultimate-express/package.json index 968b92c246e..320a482a140 100644 --- a/frameworks/JavaScript/ultimate-express/package.json +++ b/frameworks/JavaScript/ultimate-express/package.json @@ -8,11 +8,11 @@ "author": "", "license": "MIT", "dependencies": { - "fast-json-stringify": "^6.0.0", - "lru-cache": "^10.0.1", - "mariadb": "^3.2.0", - "postgres": "^3.3.5", - "ultimate-express": "^2.0.9" + "fast-json-stringify": "^6.2.0", + "lru-cache": "^11.2.4", + "mariadb": "^3.4.5", + "postgres": "^3.4.8", + "ultimate-express": "^2.0.15" }, "type": "module" } diff --git a/frameworks/JavaScript/uwebsockets.js/src/server.js b/frameworks/JavaScript/uwebsockets.js/src/server.js index 0305347a2cf..883d0de58da 100644 --- a/frameworks/JavaScript/uwebsockets.js/src/server.js +++ b/frameworks/JavaScript/uwebsockets.js/src/server.js @@ -93,7 +93,10 @@ if (db) { } }); - const extra = { id: 0, message: "Additional fortune added at request time." }; + const extra = () => ({ + id: 0, + message: "Additional fortune added at request time." + }); webserver.get("/fortunes", async (response) => { response.onAborted(() => { @@ -101,7 +104,7 @@ if (db) { }); try { - const rows = [extra, ...await db.fortunes()]; + const rows = [extra(), ...await db.fortunes()]; if (response.aborted) { return; diff --git a/frameworks/Julia/Jewelia/benchmark_config.json b/frameworks/Julia/Jewelia/benchmark_config.json index 5e918a85b4d..bfd091651dc 100644 --- a/frameworks/Julia/Jewelia/benchmark_config.json +++ b/frameworks/Julia/Jewelia/benchmark_config.json @@ -22,7 +22,8 @@ "database_os": "Linux", "display_name": "Jewelia", "notes": "", - "versus": "None" + "versus": "None", + "tags": [ "broken" ] } }] } diff --git a/frameworks/Kotlin/hexagon/build.gradle b/frameworks/Kotlin/hexagon/build.gradle index 7938c3958ac..409b3763791 100644 --- a/frameworks/Kotlin/hexagon/build.gradle +++ b/frameworks/Kotlin/hexagon/build.gradle @@ -1,7 +1,7 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "2.2.20" apply false - id "org.graalvm.buildtools.native" version "0.11.1" apply false + id "org.jetbrains.kotlin.jvm" version "2.3.0" apply false + id "org.graalvm.buildtools.native" version "0.11.3" apply false } version = "1.0.0" @@ -9,13 +9,13 @@ description = "TFB benchmark" group = "com.hexagontk" ext { - hexagonVersion = "4.2.4" - jettyVersion = "12.1.1" - nettyVersion = "4.2.6.Final" + hexagonVersion = "4.3.1" + jettyVersion = "12.1.5" + nettyVersion = "4.2.9.Final" hikariVersion = "7.0.2" postgresqlVersion = "42.7.8" - vertxVersion = "5.0.4" + vertxVersion = "5.0.6" cache2kVersion = "2.6.1.Final" applicationClass = "com.hexagontk.BenchmarkKt" @@ -30,5 +30,5 @@ subprojects { } tasks.wrapper { - gradleVersion = "9.1.0" + gradleVersion = "9.2.1" } diff --git a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75a..f8e1ee3125f 100644 Binary files a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties index 2e1113280ef..23449a2b543 100644 --- a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/ktor/benchmark_config.json b/frameworks/Kotlin/ktor/benchmark_config.json index 17373df20ee..a0ba3688aac 100644 --- a/frameworks/Kotlin/ktor/benchmark_config.json +++ b/frameworks/Kotlin/ktor/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "ktor", + "maintainers": ["ShreckYe", "inemtsev"], "tests": [ { "default": { @@ -140,7 +141,7 @@ "notes": "http://ktor.io/", "versus": "netty" }, - "exposed-dsl": { + "exposed-jdbc-dsl": { "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -157,11 +158,11 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ktor-netty-exposed-dsl", + "display_name": "ktor-netty-exposed-jdbc-dsl", "notes": "", "versus": "ktor" }, - "exposed-dao": { + "exposed-jdbc-dao": { "db_url": "/db", "fortune_url": "/fortunes", "port": 9090, @@ -176,9 +177,53 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ktor-netty-exposed-dao", + "display_name": "ktor-netty-exposed-jdbc-dao", "notes": "", "versus": "ktor" + }, + "exposed-r2dbc-dsl": { + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 9090, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "ktor", + "language": "Kotlin", + "flavor": "None", + "orm": "Full", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ktor-netty-exposed-r2dbc-dsl", + "notes": "", + "versus": "ktor" + }, + "jstach": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + + "port": 9090, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "ktor", + "language": "Kotlin", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ktor-netty-jstach", + "notes": "http://ktor.io/", + "versus": "netty" } } ] diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/README.md b/frameworks/Kotlin/ktor/ktor-asyncdb/README.md index 6b4beb607cf..efc38e7b225 100755 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/README.md +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/README.md @@ -8,24 +8,24 @@ This sets up testing using [Ktor](https://ktor.io/), with a couple of async Post ## Test URLs ### JSON -http://localhost:8080/json +http://localhost:9090/json ### PLAINTEXT -http://localhost:8080/plaintext +http://localhost:9090/plaintext ### DB -http://localhost:8080/db +http://localhost:9090/db ### QUERY -http://localhost:8080/query?queries= +http://localhost:9090/query?queries= ### UPDATE -http://localhost:8080/update?queries= +http://localhost:9090/update?queries= ### FORTUNES -http://localhost:8080/fortunes \ No newline at end of file +http://localhost:9090/fortunes \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-cio.dockerfile b/frameworks/Kotlin/ktor/ktor-cio.dockerfile index aaa05c4659b..a21a83e006a 100644 --- a/frameworks/Kotlin/ktor/ktor-cio.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-cio.dockerfile @@ -9,4 +9,4 @@ COPY --from=build /ktor/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile deleted file mode 100644 index 417c0358735..00000000000 --- a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM gradle:jdk21 - -WORKDIR /ktor-exposed -COPY ktor-exposed/settings.gradle.kts settings.gradle.kts -COPY ktor-exposed/app app -RUN gradle --no-daemon shadowJar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app/build/libs/app-all.jar", "Dao"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile deleted file mode 100644 index d89f899a9d1..00000000000 --- a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM gradle:jdk21 - -WORKDIR /ktor-exposed -COPY ktor-exposed/settings.gradle.kts settings.gradle.kts -COPY ktor-exposed/app app -RUN gradle --no-daemon shadowJar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+AlwaysPreTouch", "-jar", "app/build/libs/app-all.jar", "Dsl"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed-jdbc-dao.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-jdbc-dao.dockerfile new file mode 100644 index 00000000000..e1e5214c7ef --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed-jdbc-dao.dockerfile @@ -0,0 +1,10 @@ +FROM gradle:jdk25 + +WORKDIR /ktor-exposed +COPY ktor-exposed/settings.gradle.kts settings.gradle.kts +COPY ktor-exposed/app app +RUN gradle --no-daemon shadowJar + +EXPOSE 9090 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app/build/libs/app-all.jar", "Jdbc", "Dao"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed-jdbc-dsl.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-jdbc-dsl.dockerfile new file mode 100644 index 00000000000..4548b9aa03b --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed-jdbc-dsl.dockerfile @@ -0,0 +1,10 @@ +FROM gradle:jdk25 + +WORKDIR /ktor-exposed +COPY ktor-exposed/settings.gradle.kts settings.gradle.kts +COPY ktor-exposed/app app +RUN gradle --no-daemon shadowJar + +EXPOSE 9090 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app/build/libs/app-all.jar", "Jdbc", "Dsl"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed-r2dbc-dsl.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-r2dbc-dsl.dockerfile new file mode 100644 index 00000000000..7f3cb7a24c9 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed-r2dbc-dsl.dockerfile @@ -0,0 +1,10 @@ +FROM gradle:jdk25 + +WORKDIR /ktor-exposed +COPY ktor-exposed/settings.gradle.kts settings.gradle.kts +COPY ktor-exposed/app app +RUN gradle --no-daemon shadowJar + +EXPOSE 9090 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app/build/libs/app-all.jar", "R2dbc", "Dsl"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed/README.md b/frameworks/Kotlin/ktor/ktor-exposed/README.md index 423c8ddecd2..b4e38280b5f 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/README.md +++ b/frameworks/Kotlin/ktor/ktor-exposed/README.md @@ -15,16 +15,16 @@ The tests were run with: ## Test URLs ### DB -http://localhost:8080/db +http://localhost:9090/db ### QUERY -http://localhost:8080/query?queries= +http://localhost:9090/query?queries= ### UPDATE -http://localhost:8080/update?queries= +http://localhost:9090/update?queries= ### FORTUNES -http://localhost:8080/fortunes +http://localhost:9090/fortunes diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts index 5f29b997834..58e5e52f4d2 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts @@ -3,9 +3,9 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { application - kotlin("jvm") version "2.1.21" - kotlin("plugin.serialization") version "2.1.21" - id("com.gradleup.shadow") version "8.3.9" + kotlin("jvm") version "2.3.0" + kotlin("plugin.serialization") version "2.3.0" + id("com.gradleup.shadow") version "9.3.0" } repositories { @@ -13,8 +13,8 @@ repositories { } val ktorVersion = "3.3.3" -val kotlinxSerializationVersion = "1.8.1" -val exposedVersion = "0.61.0" +val kotlinxSerializationVersion = "1.9.0" +val exposedVersion = "1.0.0-rc-4" dependencies { implementation("io.ktor:ktor-server-core:$ktorVersion") @@ -27,20 +27,17 @@ dependencies { implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-r2dbc:${exposedVersion}") - implementation("org.postgresql:postgresql:42.7.5") - implementation("com.zaxxer:HikariCP:5.1.0") - runtimeOnly("org.slf4j:slf4j-simple:1.7.36") -} + implementation("org.postgresql:postgresql:42.7.8") + implementation("com.zaxxer:HikariCP:7.0.2") -application.mainClass.set("AppKt") + implementation("org.postgresql:r2dbc-postgresql:1.1.1.RELEASE") + implementation("io.r2dbc:r2dbc-pool:1.0.2.RELEASE") -kotlin { - jvmToolchain(21) + runtimeOnly("org.slf4j:slf4j-simple:2.0.7") } -tasks.withType().configureEach { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_21) - } -} +application.mainClass.set("AppKt") + +kotlin.jvmToolchain(25) diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt index 4b4bf93741d..216c454aef9 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt @@ -1,6 +1,8 @@ -import ExposedMode.* +import ExposedMode.Dao +import ExposedMode.Dsl import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource +import database.* import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.engine.* @@ -9,215 +11,246 @@ import io.ktor.server.netty.* import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.response.* import io.ktor.server.routing.* -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.single +import kotlinx.coroutines.flow.toList import kotlinx.html.* -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.jetbrains.exposed.dao.IntEntity -import org.jetbrains.exposed.dao.IntEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.core.vendors.PostgreSQLDialect +import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.JdbcTransaction +import org.jetbrains.exposed.v1.jdbc.transactions.suspendTransaction +import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase +import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig +import org.jetbrains.exposed.v1.r2dbc.R2dbcTransaction +import org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction import java.util.concurrent.ThreadLocalRandom +import org.jetbrains.exposed.v1.jdbc.select as jdbcSelect +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable as toJdbcExecutable +import org.jetbrains.exposed.v1.r2dbc.select as r2dbcSelect +import org.jetbrains.exposed.v1.r2dbc.statements.toExecutable as toR2dbcExecutable -@Serializable -data class World(val id: Int, var randomNumber: Int) - -@Serializable -data class Fortune(val id: Int, var message: String) - - -// see "toolset/databases/postgres/create-postgres.sql" - -object WorldTable : IdTable("World") { - override val id = integer("id").entityId() - val randomNumber = integer("randomnumber").default(0) // The name is "randomNumber" in "create-postgres.sql". -} - -object FortuneTable : IdTable("Fortune") { - override val id = integer("id").entityId() - val message = varchar("message", 2048) -} - - -class WorldDao(id: EntityID) : IntEntity(id) { - companion object : IntEntityClass(WorldTable) - - var randomNumber by WorldTable.randomNumber - fun toWorld() = - World(id.value, randomNumber) -} - -class FortuneDao(id: EntityID) : IntEntity(id) { - companion object : IntEntityClass(FortuneTable) - - var message by FortuneTable.message - fun toFortune() = - Fortune(id.value, message) +enum class ConnectionMode { + Jdbc, R2dbc } - enum class ExposedMode { Dsl, Dao } fun main(args: Array) { - val exposedMode = valueOf(args.first()) - embeddedServer(Netty, port = 9090) { module(exposedMode) }.start(wait = true) + val connectionMode = ConnectionMode.valueOf(args[0]) + val exposedMode = ExposedMode.valueOf(args[1]) + embeddedServer(Netty, port = 9090) { module(connectionMode, exposedMode) }.start(wait = true) } -fun Application.module(exposedMode: ExposedMode) { - val poolSize = Runtime.getRuntime().availableProcessors() * 2 - val pool = HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) - val database = Database.connect(pool) - val databaseDispatcher = Dispatchers.IO.limitedParallelism(poolSize) - suspend fun withDatabaseTransaction(statement: suspend Transaction.() -> T) = - newSuspendedTransaction(context = databaseDispatcher, db = database, statement = statement) - install(DefaultHeaders) +fun Application.module(connectionMode: ConnectionMode, exposedMode: ExposedMode) = + parameterizedModule( + when (connectionMode) { + ConnectionMode.Jdbc -> when (exposedMode) { + Dsl -> ExposedOps.Jdbc.Dsl + Dao -> ExposedOps.Jdbc.Dao + } - routing { - fun selectWorldsWithIdQuery(id: Int) = - WorldTable.select(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) + ConnectionMode.R2dbc -> when (exposedMode) { + Dsl -> ExposedOps.R2dbc.Dsl + Dao -> throw IllegalArgumentException("DAO with R2DBC is not supported") + } + } + ) - fun ResultRow.toWorld() = - World(this[WorldTable.id].value, this[WorldTable.randomNumber]) +fun ApplicationCall.queries() = + request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 - fun ResultRow.toFortune() = - Fortune(this[FortuneTable.id].value, this[FortuneTable.message]) +private const val DB_ROWS = 10_000 +fun ThreadLocalRandom.nextIntWithinRows() = + nextInt(DB_ROWS) + 1 + +interface ExposedOps { + fun createDatabase(): TDatabase + suspend fun transaction(db: TDatabase, statement: suspend TTransaction.() -> T): T + + // Repository pattern functions. These can also be extracted into a separate interface. + suspend fun TTransaction.getWorldWithId(id: Int): World + suspend fun TTransaction.getRandomWorlds(queries: Int, random: ThreadLocalRandom): List + suspend fun TTransaction.getAllFortunesAndAddTo(result: MutableList) + suspend fun TTransaction.getRandomWorldsAndUpdate(queries: Int, random: ThreadLocalRandom): List + + interface Jdbc : ExposedOps { + override fun createDatabase(): Database { + val poolSize = Runtime.getRuntime().availableProcessors() * 2 + val pool = HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) + return Database.connect(pool) + } - fun ThreadLocalRandom.nextIntWithinRows() = - nextInt(DB_ROWS) + 1 + override suspend fun transaction(db: Database, statement: suspend JdbcTransaction.() -> T): T = + suspendTransaction(db) { statement() } - fun selectSingleWorld(random: ThreadLocalRandom): World = - selectWorldsWithIdQuery(random.nextIntWithinRows()).single().toWorld() + object Dsl : Jdbc { + override suspend fun JdbcTransaction.getWorldWithId(id: Int): World = + WorldTable.jdbcSelect(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) + .single().toWorld() - fun selectWorlds(queries: Int, random: ThreadLocalRandom): List = - List(queries) { selectSingleWorld(random) } + override suspend fun JdbcTransaction.getRandomWorlds(queries: Int, random: ThreadLocalRandom): List = + // Coroutine concurrent `select`s lead to connection pool exhaustion. + List(queries) { getWorldWithId(random.nextIntWithinRows()) } - get("/db") { - val random = ThreadLocalRandom.current() - val result = withDatabaseTransaction { - when (exposedMode) { - Dsl -> selectSingleWorld(random) - Dao -> WorldDao[random.nextIntWithinRows()].toWorld() - } + override suspend fun JdbcTransaction.getAllFortunesAndAddTo(result: MutableList) { + FortuneTable.jdbcSelect(FortuneTable.id, FortuneTable.message) + .mapTo(result) { it.toFortune() } } - call.respondText(Json.encodeToString(result), ContentType.Application.Json) - } - - get("/queries") { - val queries = call.queries() - val random = ThreadLocalRandom.current() - - val result = withDatabaseTransaction { - when (exposedMode) { - Dsl -> selectWorlds(queries, random) - Dao -> //List(queries) { WorldDao[random.nextIntWithinRows()].toWorld() } - throw IllegalArgumentException("DAO not supported because it appears to cache results") + override suspend fun JdbcTransaction.getRandomWorldsAndUpdate( + queries: Int, random: ThreadLocalRandom + ): List { + val result = getRandomWorlds(queries, random) + result.forEach { it.randomNumber = random.nextIntWithinRows() } + val batch = BatchUpdateStatement(WorldTable) + result.sortedBy { it.id }.forEach { world -> + batch.addBatch(EntityID(world.id, WorldTable)) + batch[WorldTable.randomNumber] = world.randomNumber } + // also consider passing the transaction explicitly + batch.toJdbcExecutable().execute(this) + return result } - - call.respondText(Json.encodeToString(result), ContentType.Application.Json) } - get("/fortunes") { - val result = withDatabaseTransaction { - when (exposedMode) { - Dsl -> FortuneTable.select(FortuneTable.id, FortuneTable.message) - .asSequence().map { it.toFortune() } + object Dao : Jdbc { + override suspend fun JdbcTransaction.getWorldWithId(id: Int): World = + WorldDao[id].toWorld() - Dao -> FortuneDao.all().asSequence().map { it.toFortune() } - }.toMutableList() + override suspend fun JdbcTransaction.getRandomWorlds(queries: Int, random: ThreadLocalRandom): List = + //List(queries) { WorldDao[random.nextIntWithinRows()].toWorld() } + throw IllegalArgumentException("DAO not supported because it appears to cache results") + + override suspend fun JdbcTransaction.getAllFortunesAndAddTo(result: MutableList) { + FortuneDao.all().mapTo(result) { it.toFortune() } } - result.add(Fortune(0, "Additional fortune added at request time.")) - result.sortBy { it.message } - call.respondHtml { - head { title { +"Fortunes" } } - body { - table { - tr { - th { +"id" } - th { +"message" } - } - for (fortune in result) { - tr { - td { +fortune.id.toString() } - td { +fortune.message } - } - } + override suspend fun JdbcTransaction.getRandomWorldsAndUpdate( + queries: Int, random: ThreadLocalRandom + ): List { + /* + val worldDaosAndNewRandomNumbers = + List(queries) { WorldDao[random.nextIntWithinRows()] to random.nextIntWithinRows() } + worldDaosAndNewRandomNumbers + .sortedBy { (worldDao, _) -> worldDao.id.value } + .forEach { (worldDao, newRandomNumber) -> + worldDao.randomNumber = newRandomNumber } - } + val result = worldDaosAndNewRandomNumbers.map { (worldDao, _) -> worldDao.toWorld() } + */ + throw IllegalArgumentException("DAO not supported because it appears to cache results") } } + } - get("/updates") { - val queries = call.queries() - val random = ThreadLocalRandom.current() - lateinit var result: List - - withDatabaseTransaction { - when (exposedMode) { - Dsl -> { - result = selectWorlds(queries, random) - result.forEach { it.randomNumber = random.nextIntWithinRows() } - val batch = BatchUpdateStatement(WorldTable) - result.sortedBy { it.id }.forEach { world -> - batch.addBatch(EntityID(world.id, WorldTable)) - batch[WorldTable.randomNumber] = world.randomNumber - } - batch.execute(TransactionManager.current()) - } + // TODO consider moving to separate files to avoid import conflicts/aliases + interface R2dbc : ExposedOps { + override fun createDatabase(): R2dbcDatabase = + R2dbcDatabase.connect(configurePostgresR2DBC(), R2dbcDatabaseConfig { + // This can't be omitted. + explicitDialect = PostgreSQLDialect() + }) + + override suspend fun transaction(db: R2dbcDatabase, statement: suspend R2dbcTransaction.() -> T): T = + suspendTransaction(db) { statement() } + + object Dsl : R2dbc { + override suspend fun R2dbcTransaction.getWorldWithId(id: Int): World = + WorldTable.r2dbcSelect(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) + .single().toWorld() + + override suspend fun R2dbcTransaction.getRandomWorlds( + queries: Int, + random: ThreadLocalRandom + ): List = + // Coroutine concurrent `select`s lead to connection pool exhaustion. + List(queries) { getWorldWithId(random.nextIntWithinRows()) } + + override suspend fun R2dbcTransaction.getAllFortunesAndAddTo(result: MutableList) { + FortuneTable.r2dbcSelect(FortuneTable.id, FortuneTable.message) + .map { it.toFortune() }.toList(result) + } - Dao -> /*{ - val worldDaosAndNewRandomNumbers = - List(queries) { WorldDao[random.nextIntWithinRows()] to random.nextIntWithinRows() } - worldDaosAndNewRandomNumbers - .sortedBy { (worldDao, _) -> worldDao.id.value } - .forEach { (worldDao, newRandomNumber) -> - worldDao.randomNumber = newRandomNumber - } - result = worldDaosAndNewRandomNumbers.map { (worldDao, _) -> worldDao.toWorld() } - }*/ - throw IllegalArgumentException("DAO not supported because it appears to cache results") + override suspend fun R2dbcTransaction.getRandomWorldsAndUpdate( + queries: Int, + random: ThreadLocalRandom + ): List { + val result = getRandomWorlds(queries, random) + result.forEach { it.randomNumber = random.nextIntWithinRows() } + val batch = BatchUpdateStatement(WorldTable) + result.sortedBy { it.id }.forEach { world -> + batch.addBatch(EntityID(world.id, WorldTable)) + batch[WorldTable.randomNumber] = world.randomNumber } + batch.toR2dbcExecutable().execute(this) + return result } - - call.respondText(Json.encodeToString(result), ContentType.Application.Json) } } } -private const val DB_ROWS = 10_000 +fun Application.parameterizedModule(exposedOps: ExposedOps) { + install(DefaultHeaders) -fun HikariConfig.configurePostgres(poolSize: Int) { - jdbcUrl = "jdbc:postgresql://tfb-database/hello_world?useSSL=false" - driverClassName = org.postgresql.Driver::class.java.name + routing { + with(exposedOps) { + val database = createDatabase() - configureCommon(poolSize) -} + suspend fun transaction(statement: suspend TTransaction.() -> T): T = + transaction(database, statement) -fun HikariConfig.configureCommon(poolSize: Int) { - username = "benchmarkdbuser" - password = "benchmarkdbpass" - addDataSourceProperty("cacheServerConfiguration", true) - addDataSourceProperty("cachePrepStmts", "true") - addDataSourceProperty("useUnbufferedInput", "false") - addDataSourceProperty("prepStmtCacheSize", "4096") - addDataSourceProperty("prepStmtCacheSqlLimit", "2048") - connectionTimeout = 10000 - maximumPoolSize = poolSize - minimumIdle = poolSize -} + get("/db") { + val random = ThreadLocalRandom.current() + val result = transaction { getWorldWithId(random.nextIntWithinRows()) } + call.respondText(json.encodeToString(result), ContentType.Application.Json) + } -fun ApplicationCall.queries() = - request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 + get("/queries") { + val queries = call.queries() + val random = ThreadLocalRandom.current() + val result = transaction { getRandomWorlds(queries, random) } + call.respondText(json.encodeToString(result), ContentType.Application.Json) + } + + get("/fortunes") { + val result = mutableListOf() + + transaction { getAllFortunesAndAddTo(result) } + + result.add(Fortune(0, "Additional fortune added at request time.")) + result.sortBy { it.message } + + call.respondHtml { + head { title { +"Fortunes" } } + body { + table { + tr { + th { +"id" } + th { +"message" } + } + for (fortune in result) { + tr { + td { +fortune.id.toString() } + td { +fortune.message } + } + } + } + } + } + } + get("/updates") { + val queries = call.queries() + val random = ThreadLocalRandom.current() + val result = transaction { getRandomWorldsAndUpdate(queries, random) } + call.respondText(json.encodeToString(result), ContentType.Application.Json) + } + } + } +} diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/Json.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/Json.kt new file mode 100644 index 00000000000..53f3bf19c06 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/Json.kt @@ -0,0 +1,10 @@ +import kotlinx.serialization.json.Json + +// copied from the `ktor` portion +// Optimized JSON instance with better performance settings +internal val json = Json { + prettyPrint = false + isLenient = true + ignoreUnknownKeys = true + coerceInputValues = true +} diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/Models.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/Models.kt new file mode 100644 index 00000000000..9791ee4a7fa --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/Models.kt @@ -0,0 +1,7 @@ +import kotlinx.serialization.Serializable + +@Serializable +data class World(val id: Int, var randomNumber: Int) + +@Serializable +data class Fortune(val id: Int, var message: String) diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/Exposed.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/Exposed.kt new file mode 100644 index 00000000000..ef400c54b03 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/Exposed.kt @@ -0,0 +1,45 @@ +package database + +import Fortune +import World +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.dao.id.IdTable +import org.jetbrains.exposed.v1.dao.IntEntity +import org.jetbrains.exposed.v1.dao.IntEntityClass + +// see "toolset/databases/postgres/create-postgres.sql" + +object WorldTable : IdTable("World") { + override val id = integer("id").entityId() + val randomNumber = integer("randomnumber").default(0) // The name is "randomNumber" in "create-postgres.sql". +} + +object FortuneTable : IdTable("Fortune") { + override val id = integer("id").entityId() + val message = varchar("message", 2048) +} + + +fun ResultRow.toWorld() = + World(this[WorldTable.id].value, this[WorldTable.randomNumber]) + +fun ResultRow.toFortune() = + Fortune(this[FortuneTable.id].value, this[FortuneTable.message]) + + +class WorldDao(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(WorldTable) + + var randomNumber by WorldTable.randomNumber + fun toWorld() = + World(id.value, randomNumber) +} + +class FortuneDao(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(FortuneTable) + + var message by FortuneTable.message + fun toFortune() = + Fortune(id.value, message) +} diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/Jdbc.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/Jdbc.kt new file mode 100644 index 00000000000..26044113374 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/Jdbc.kt @@ -0,0 +1,28 @@ +package database + +import com.zaxxer.hikari.HikariConfig + +// copied from the `ktor` portion + +fun HikariConfig.configurePostgres(poolSize: Int) { + jdbcUrl = "jdbc:postgresql://tfb-database:5432/hello_world?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable" + driverClassName = org.postgresql.Driver::class.java.name + configureCommon(poolSize) +} + +fun HikariConfig.configureCommon(poolSize: Int) { + username = "benchmarkdbuser" + password = "benchmarkdbpass" + addDataSourceProperty("cacheServerConfiguration", true) + addDataSourceProperty("cachePrepStmts", "true") + addDataSourceProperty("useUnbufferedInput", "false") + addDataSourceProperty("prepStmtCacheSize", "4096") + addDataSourceProperty("prepStmtCacheSqlLimit", "2048") + connectionTimeout = 5000 + maximumPoolSize = poolSize + minimumIdle = poolSize + idleTimeout = 300000 // 5 minutes + maxLifetime = 600000 // 10 minutes + validationTimeout = 5000 + leakDetectionThreshold = 60000 +} diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/R2dbc.kt b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/R2dbc.kt new file mode 100644 index 00000000000..63b80ccaafa --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/database/R2dbc.kt @@ -0,0 +1,37 @@ +package database + +import io.r2dbc.pool.ConnectionPool +import io.r2dbc.pool.ConnectionPoolConfiguration +import io.r2dbc.postgresql.PostgresqlConnectionConfiguration +import io.r2dbc.postgresql.PostgresqlConnectionFactory +import io.r2dbc.postgresql.client.SSLMode +import io.r2dbc.spi.ConnectionFactory +import java.time.Duration + +// copied and adapted from the `ktor-r2dbc` portion + +fun configurePostgresR2DBC(): ConnectionFactory { + val cfo = PostgresqlConnectionConfiguration.builder() + .host("tfb-database") + .port(5432) + .database("hello_world") + .username("benchmarkdbuser") + .password("benchmarkdbpass") + //.loopResources { NioClientEventLoopResources(Runtime.getRuntime().availableProcessors()).cacheLoops() } + .sslMode(SSLMode.DISABLE) + .tcpKeepAlive(true) + .tcpNoDelay(true) + .build() + + val cf = PostgresqlConnectionFactory(cfo) + + val cp = ConnectionPoolConfiguration.builder(cf) + .initialSize(512) + .maxSize(512) + .maxIdleTime(Duration.ofSeconds(30)) + .maxAcquireTime(Duration.ofSeconds(5)) + .validationQuery("SELECT 1") + .build() + + return ConnectionPool(cp) +} diff --git a/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.jar index ccebba7710d..f8e1ee3125f 100644 Binary files a/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties index 18362b78bde..23449a2b543 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/ktor/ktor-exposed/gradlew b/frameworks/Kotlin/ktor/ktor-exposed/gradlew index 79a61d421cc..adff685a034 100755 --- a/frameworks/Kotlin/ktor/ktor-exposed/gradlew +++ b/frameworks/Kotlin/ktor/ktor-exposed/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -133,10 +132,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -169,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -197,16 +198,19 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/frameworks/Kotlin/ktor/ktor-exposed/gradlew.bat b/frameworks/Kotlin/ktor/ktor-exposed/gradlew.bat index 93e3f59f135..c4bdd3ab8e3 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/gradlew.bat +++ b/frameworks/Kotlin/ktor/ktor-exposed/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile index be5f6dd4606..054e1effbe2 100644 --- a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile @@ -12,4 +12,4 @@ COPY --from=build /app/build/libs/ktor-asyncdb.jar ktor-asyncdb.jar EXPOSE 9090 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-asyncdb.jar", "jasync-sql"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "ktor-asyncdb.jar", "jasync-sql"] diff --git a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile index c8fd555f50f..b4756a08bd1 100644 --- a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile @@ -9,4 +9,4 @@ COPY --from=build /ktor/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-jstach.dockerfile b/frameworks/Kotlin/ktor/ktor-jstach.dockerfile new file mode 100644 index 00000000000..2a50596112a --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach.dockerfile @@ -0,0 +1,12 @@ +FROM gradle:8.13-jdk21 AS build +WORKDIR /ktor-jstach +COPY ktor-jstach/ ./ +RUN chmod +x gradlew && ./gradlew --no-daemon clean nettyBundle + +FROM amazoncorretto:21-al2023-headless +WORKDIR /ktor-jstach +COPY --from=build /ktor-jstach/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar + +EXPOSE 9090 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-jstach/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-jstach/build.gradle.kts new file mode 100644 index 00000000000..446d09b9dbb --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/build.gradle.kts @@ -0,0 +1,91 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "2.1.21" + kotlin("kapt") version "2.1.21" + kotlin("plugin.serialization") version "2.1.21" + id("com.gradleup.shadow") version "8.3.9" +} + +group = "org.jetbrains.ktor" +version = "1.0-SNAPSHOT" + +val ktorVersion = "3.3.3" +val serializationVersion = "1.8.1" +val hikariVersion = "5.1.0" +val logbackVersion = "1.5.13" +val mysqlVersion = "8.0.33" +val postgresqlVersion = "42.7.5" +val jstachioVersion = "1.3.6" + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib")) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion") + + implementation("io.ktor:ktor-server-default-headers-jvm:$ktorVersion") + implementation("io.ktor:ktor-server-netty-jvm:$ktorVersion") + + implementation("com.zaxxer:HikariCP:$hikariVersion") + implementation("ch.qos.logback:logback-classic:$logbackVersion") + + implementation("org.postgresql:postgresql:$postgresqlVersion") + implementation("mysql:mysql-connector-java:$mysqlVersion") + + implementation("io.jstach:jstachio:$jstachioVersion") + kapt("io.jstach:jstachio-apt:$jstachioVersion") +} + +kotlin { + jvmToolchain(21) +} + +tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } +} + +tasks.named("shadowJar") { + enabled = false +} + +fun registerBundle( + name: String, + classifier: String, + mainClass: String, + exclusions: List +) = tasks.register(name, ShadowJar::class) { + archiveBaseName.set("tech-empower-framework-benchmark") + archiveVersion.set(project.version.toString()) + archiveClassifier.set(classifier) + manifest { + attributes["Main-Class"] = mainClass + } + from(sourceSets.main.get().output) + configurations = listOf(project.configurations.runtimeClasspath.get()) + dependencies { + exclusions.forEach { exclude(dependency(it)) } + } + exclude("META-INF/*.SF") + exclude("META-INF/*.DSA") + exclude("META-INF/*.RSA") + mergeServiceFiles() +} + +val nettyBundle by registerBundle( + name = "nettyBundle", + classifier = "netty-bundle", + mainClass = "io.ktor.server.netty.EngineMain", + exclusions = emptyList() +) + +tasks.named("build") { + dependsOn(nettyBundle) +} diff --git a/frameworks/Kotlin/ktor/ktor-jstach/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/ktor/ktor-jstach/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..28861d273a5 Binary files /dev/null and b/frameworks/Kotlin/ktor/ktor-jstach/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/ktor/ktor-jstach/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-jstach/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..e6045a98350 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip diff --git a/frameworks/Kotlin/ktor/ktor-jstach/gradlew b/frameworks/Kotlin/ktor/ktor-jstach/gradlew new file mode 100755 index 00000000000..cccdd3d517f --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/frameworks/Kotlin/ktor/ktor-jstach/gradlew.bat b/frameworks/Kotlin/ktor/ktor-jstach/gradlew.bat new file mode 100644 index 00000000000..e95643d6a2c --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt new file mode 100644 index 00000000000..e844ebc202e --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt @@ -0,0 +1,28 @@ +package org.jetbrains.ktor.benchmarks + +import com.zaxxer.hikari.HikariConfig + +fun HikariConfig.configurePostgres(poolSize: Int) { + jdbcUrl = "jdbc:postgresql://tfb-database:5432/hello_world?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable" + driverClassName = org.postgresql.Driver::class.java.name + configureCommon(poolSize) +} + +fun HikariConfig.configureCommon(poolSize: Int) { + username = "benchmarkdbuser" + password = "benchmarkdbpass" + addDataSourceProperty("cacheServerConfiguration", true) + connectionTimeout = 5000 + maximumPoolSize = poolSize + minimumIdle = poolSize + idleTimeout = 300000 // 5 minutes + maxLifetime = 600000 // 10 minutes + validationTimeout = 5000 + leakDetectionThreshold = 60000 +} + +fun HikariConfig.configureMySql(poolSize: Int) { + jdbcUrl = "jdbc:mysql://tfb-database:3306/hello_world?useSSL=false" + driverClassName = com.mysql.jdbc.Driver::class.java.name + configureCommon(poolSize) +} diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Fortunes.kt b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Fortunes.kt new file mode 100644 index 00000000000..c16b0940280 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Fortunes.kt @@ -0,0 +1,6 @@ +package org.jetbrains.ktor.benchmarks + +import io.jstach.jstache.JStache + +@JStache(path = "fortunes.mustache") +data class Fortunes(val fortunes: List) diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt new file mode 100644 index 00000000000..73461f75e66 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt @@ -0,0 +1,12 @@ +package org.jetbrains.ktor.benchmarks + +import kotlinx.serialization.Serializable + +@Serializable +data class Message(val message: String) + +@Serializable +data class World(val id: Int, var randomNumber: Int) + +@Serializable +data class Fortune(val id: Int, var message: String) diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt new file mode 100644 index 00000000000..600bc08f2f0 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt @@ -0,0 +1,22 @@ +package org.jetbrains.ktor.benchmarks + +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.serialization.json.Json + +// Optimized JSON instance with better performance settings +internal val json = Json { + prettyPrint = false + isLenient = true + ignoreUnknownKeys = true + coerceInputValues = true +} + +internal suspend inline fun RoutingCall.respondJson(response: E) { + respond(TextContent( + json.encodeToString(response), + ContentType.Application.Json + )) +} diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt new file mode 100644 index 00000000000..17505e96aa0 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt @@ -0,0 +1,148 @@ +package org.jetbrains.ktor.benchmarks + +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.server.application.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.jstach.jstachio.JStachio +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.withContext +import java.util.StringJoiner +import java.util.concurrent.ThreadLocalRandom +import kotlinx.coroutines.CoroutineDispatcher + +const val HELLO_WORLD = "Hello, World!" +const val WORLD_QUERY = "SELECT id, randomNumber FROM World WHERE id = ?" +const val FORTUNES_QUERY = "SELECT id, message FROM fortune" +const val DB_ROWS = 10_000 + +@OptIn(ExperimentalCoroutinesApi::class) +fun Application.main() { + val poolSize = Runtime.getRuntime().availableProcessors() * 2 + val pool = HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) + + // Create a dedicated dispatcher for database operations + val databaseDispatcher = Dispatchers.IO.limitedParallelism(poolSize) + val helloWorldContent = TextContent(HELLO_WORLD, ContentType.Text.Plain) + + install(DefaultHeaders) + + routing { + get("/plaintext") { + call.respond(helloWorldContent) + } + + get("/json") { + call.respondJson(Message(HELLO_WORLD)) + } + + get("/db") { + val world = fetchWorld(pool, databaseDispatcher) + call.respondJson(world) + } + + get("/queries") { + val queries = call.queries() + val result = fetchWorlds(pool, queries, databaseDispatcher) + call.respondJson(result) + } + + get("/fortunes") { + val result = mutableListOf() + withContext(databaseDispatcher) { + pool.connection.use { connection -> + connection.prepareStatement(FORTUNES_QUERY).use { statement -> + statement.executeQuery().use { rs -> + while (rs.next()) { + result += Fortune(rs.getInt(1), rs.getString(2)) + } + } + } + } + } + result.add(Fortune(0, "Additional fortune added at request time.")) + result.sortBy { it.message } + call.respondText(JStachio.render(Fortunes(result)), ContentType.Text.Html) + } + + get("/updates") { + val queries = call.queries() + val result = fetchWorlds(pool, queries, databaseDispatcher) + + withContext(databaseDispatcher) { + pool.connection.use { connection -> + val updateSql = StringJoiner( + ", ", + "UPDATE World SET randomNumber = temp.randomNumber FROM (VALUES ", + " ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = World.id" + ) + + for (world in result) { + world.randomNumber = ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1) + updateSql.add("(?, ?)") + } + + connection.prepareStatement(updateSql.toString()).use { statement -> + var paramIndex = 0 + for (world in result) { + statement.setInt(++paramIndex, world.id) + statement.setInt(++paramIndex, world.randomNumber) + } + statement.executeUpdate() + } + } + } + + call.respondJson(result) + } + } +} + +suspend fun fetchWorld( + pool: HikariDataSource, + dispatcher: CoroutineDispatcher +): World = withContext(dispatcher) { + pool.connection.use { connection -> + fetchWorld(connection) + } +} + +private fun fetchWorld(connection: java.sql.Connection): World = + connection.prepareStatement(WORLD_QUERY).use { statement -> + statement.setInt(1, ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1)) + statement.executeQuery().use { rs -> + rs.next() + World(rs.getInt(1), rs.getInt(2)) + } + } + +suspend fun fetchWorlds( + pool: HikariDataSource, + queries: Int, + dispatcher: CoroutineDispatcher +): Array = withContext(dispatcher) { + if (queries <= 0) { + emptyArray() + } else { + pool.connection.use { connection -> + connection.prepareStatement(WORLD_QUERY).use { statement -> + Array(queries) { + statement.setInt(1, ThreadLocalRandom.current().nextInt(1, DB_ROWS + 1)) + statement.executeQuery().use { rs -> + rs.next() + World(rs.getInt(1), rs.getInt(2)) + } + } + } + } + } +} + + +fun ApplicationCall.queries() = + request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/application.conf new file mode 100644 index 00000000000..ad26f4f1ddc --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/application.conf @@ -0,0 +1,12 @@ +ktor { + deployment { + port = 9090 + autoreload = false + watch = [ ] + shareWorkGroup = true + } + + application { + modules = [org.jetbrains.ktor.benchmarks.MainKt.main] + } +} diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/fortunes.mustache b/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/fortunes.mustache new file mode 100644 index 00000000000..3043546205b --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/fortunes.mustache @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + {{#fortunes}} + + + + + {{/fortunes}} +
idmessage
{{id}}{{message}}
+ + diff --git a/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/logback.xml b/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/logback.xml new file mode 100644 index 00000000000..912e1f1e3bf --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-jstach/src/main/resources/logback.xml @@ -0,0 +1,20 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + true + + + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile index dfee699ede7..e3bf848c892 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile @@ -12,4 +12,4 @@ COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "ktor-pgclient.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile index 9aa09916483..6eeefe687ec 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile @@ -9,4 +9,4 @@ COPY --from=build /ktor-r2dbc/build/libs/tech-empower-framework-benchmark-1.0-SN EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index 54a77082a07..fee924bbac4 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -107,8 +107,8 @@ fun Application.main() { .then(Mono.from(connection.commitTransaction())) }, Connection::close, - { connection, _ -> connection.rollbackTransaction() }, - { connection -> connection.rollbackTransaction() } + { connection, _ -> Mono.from(connection.rollbackTransaction()).then(Mono.from(connection.close())) }, + { connection -> Mono.from(connection.rollbackTransaction()).then(Mono.from(connection.close())) } ).awaitFirstOrNull() call.respondJson(updatedWorlds) @@ -126,11 +126,14 @@ private suspend fun ConnectionFactory.fetchWorlds( ): List { if (count <= 0) return emptyList() val concurrency = min(count, 32) - return Mono.usingWhen(create(), { connection -> - Flux.range(0, count) - .flatMap({ selectWorldPublisher(connection) }, concurrency) - .collectList() - }, Connection::close).awaitSingle() + return Flux.range(0, count) + .flatMap({ + Mono.usingWhen(create(), { connection -> + selectWorldPublisher(connection) + }, Connection::close) + }, concurrency) + .collectList() + .awaitSingle() } private fun selectWorld(connection: Connection): Mono = @@ -186,7 +189,6 @@ private fun configurePostgresR2DBC(config: ApplicationConfig): ConnectionFactory .maxSize(config.property("db.maxPoolSize").getString().toInt()) .maxIdleTime(Duration.ofSeconds(30)) .maxAcquireTime(Duration.ofSeconds(5)) - .validationQuery("SELECT 1") .build() return ConnectionPool(cp) diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf index fe2031a7699..cd083fdf34e 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf @@ -18,8 +18,8 @@ db { host = "tfb-database" port = 5432 database = "hello_world" - initPoolSize = 512 - maxPoolSize = 512 + initPoolSize = 32 + maxPoolSize = 256 username = "benchmarkdbuser" password = "benchmarkdbpass" //url = "r2dbc:postgresql://"${db.host}":"${db.port}"/"${db.database}"?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable&maxSize="${db.poolSize} diff --git a/frameworks/Kotlin/ktor/ktor.dockerfile b/frameworks/Kotlin/ktor/ktor.dockerfile index d0d81f0217f..539ded27501 100644 --- a/frameworks/Kotlin/ktor/ktor.dockerfile +++ b/frameworks/Kotlin/ktor/ktor.dockerfile @@ -9,4 +9,4 @@ COPY --from=build /ktor/build/libs/tech-empower-framework-benchmark-1.0-SNAPSHOT EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-Djava.lang.Integer.IntegerCache.high=10000", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt index ee57ad5126d..8ba28da0fbc 100644 --- a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt +++ b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt @@ -3,7 +3,7 @@ package org.jetbrains.ktor.benchmarks import com.zaxxer.hikari.HikariConfig fun HikariConfig.configurePostgres(poolSize: Int) { - jdbcUrl = "jdbc:postgresql://tfb-database/hello_world?useSSL=false" + jdbcUrl = "jdbc:postgresql://tfb-database:5432/hello_world?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable" driverClassName = org.postgresql.Driver::class.java.name configureCommon(poolSize) } diff --git a/frameworks/Kotlin/pellet/README.md b/frameworks/Kotlin/pellet/README.md deleted file mode 100755 index da2635f2f39..00000000000 --- a/frameworks/Kotlin/pellet/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Pellet - -[Pellet](https://www.pellet.dev) is an opinionated, Kotlin-first web framework that helps you write fast, concise, and correct backend services 🚀. - -This is a simple set of benchmarks as part of the TechEmpower Web Framework Benchmarks suite. - -The suite currently includes the plaintext, JSON serialization, single query, multiple query, database updates, and fortunes tests. - -All routes are contained within the [Benchmark.kt](sample/src/main/kotlin/benchmark/Benchmark.kt) file. - -## Test URLs - -### Plaintext - -http://localhost:8080/plaintext - -### JSON Serialization - -http://localhost:8080/json - -### Single Query - -http://localhost:8080/db - -### Multiple Queries - -http://localhost:8080/queries - -### Database Updates - -http://localhost:8080/updates - -### Fortunes - -http://localhost:8080/fortunes diff --git a/frameworks/Kotlin/pellet/benchmark_config.json b/frameworks/Kotlin/pellet/benchmark_config.json deleted file mode 100755 index fff2e4f1056..00000000000 --- a/frameworks/Kotlin/pellet/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "pellet", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/query?queries=", - "update_url": "/updates?queries=", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "Pellet", - "language": "Kotlin", - "flavor": "None", - "orm": "micro", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Pellet", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Kotlin/pellet/pellet.dockerfile b/frameworks/Kotlin/pellet/pellet.dockerfile deleted file mode 100644 index 3600569ea35..00000000000 --- a/frameworks/Kotlin/pellet/pellet.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM gradle:jdk21 as gradle -WORKDIR /sample -COPY sample/build.gradle.kts build.gradle.kts -COPY sample/src src -RUN gradle clean shadowJar --no-daemon - -FROM openjdk:22-jdk-buster -WORKDIR /sample -COPY --from=gradle /sample/build/libs/sample-1.0.0-all.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/pellet/sample/build.gradle.kts b/frameworks/Kotlin/pellet/sample/build.gradle.kts deleted file mode 100644 index f12dad8adbd..00000000000 --- a/frameworks/Kotlin/pellet/sample/build.gradle.kts +++ /dev/null @@ -1,53 +0,0 @@ -plugins { - application - id("com.github.johnrengelman.shadow") version "7.1.0" - kotlin("jvm") version "1.9.23" - kotlin("plugin.serialization") version "1.9.23" - id("nu.studer.rocker") version "3.0.4" -} - -group = "benchmark" -version = "1.0.0" - -repositories { - mavenCentral() -} - -rocker { - version.set("1.3.0") - configurations { - create("main") { - optimize.set(true) - templateDir.set(file("src/main/resources")) - outputDir.set(file("src/generated/rocker")) - } - } -} - -dependencies { - implementation(platform("dev.pellet:pellet-bom:0.0.16")) - implementation("dev.pellet:pellet-server") - implementation("dev.pellet:pellet-logging") - implementation("org.slf4j:slf4j-api:1.7.36") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") - implementation(platform(kotlin("bom"))) - implementation(kotlin("stdlib-jdk8")) - implementation("io.vertx:vertx-pg-client:4.5.5") - implementation("io.vertx:vertx-lang-kotlin:4.5.5") - implementation("com.ongres.scram:client:2.1") -} - -java { - toolchain { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 - } -} - -tasks.withType { - kotlinOptions.jvmTarget = "21" -} - -application { - mainClass.set("benchmark.BenchmarkKt") -} diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt deleted file mode 100644 index 51dd307d511..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt +++ /dev/null @@ -1,151 +0,0 @@ -package benchmark - -import benchmark.data.Fortune -import benchmark.data.TFBRepository -import com.fizzed.rocker.runtime.StringBuilderOutput -import dev.pellet.logging.pelletLogger -import dev.pellet.server.PelletBuilder.httpRouter -import dev.pellet.server.PelletBuilder.pelletServer -import dev.pellet.server.PelletConnector -import dev.pellet.server.codec.mime.MediaType -import dev.pellet.server.responder.http.PelletHTTPRouteContext -import dev.pellet.server.routing.http.HTTPRouteResponse -import kotlinx.serialization.json.Json -import java.time.Instant -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.util.Locale -import java.util.concurrent.ThreadLocalRandom - -object Benchmark - -val logger = pelletLogger() -val jsonEncoder = Json { - prettyPrint = false -} - -fun main() { - val sharedRouter = httpRouter { - get("/plaintext", ::handlePlain) - get("/json", ::handleJson) - get("/db", ::handleDb) - get("/query", ::handleQuery) - get("/updates", ::handleUpdates) - get("/fortunes", ::handleFortunes) - } - val pellet = pelletServer { - logRequests = false - httpConnector { - endpoint = PelletConnector.Endpoint( - hostname = "0.0.0.0", - port = 8080 - ) - router = sharedRouter - } - } - pellet.start() -} - -val dateFormatter = DateTimeFormatter - .ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH) - .withZone(ZoneId.of("GMT")) - -private fun handlePlain( - context: PelletHTTPRouteContext -): HTTPRouteResponse { - return HTTPRouteResponse.Builder() - .statusCode(200) - .entity("Hello, World!", MediaType("text", "plain")) - .header("Server", "pellet") - .header("Date", dateFormatter.format(Instant.now())) - .build() -} - -@kotlinx.serialization.Serializable -data class ResponseBody( - val message: String -) - -private fun handleJson( - context: PelletHTTPRouteContext -): HTTPRouteResponse { - val responseBody = ResponseBody(message = "Hello, World!") - return HTTPRouteResponse.Builder() - .statusCode(200) - .jsonEntity(jsonEncoder, responseBody) - .header("Server", "pellet") - .header("Date", dateFormatter.format(Instant.now())) - .build() -} - -private val repository = TFBRepository() - -private fun handleDb( - context: PelletHTTPRouteContext -): HTTPRouteResponse { - val result = repository.fetchWorld() - return HTTPRouteResponse.Builder() - .statusCode(200) - .jsonEntity(jsonEncoder, result) - .header("Server", "pellet") - .header("Date", dateFormatter.format(Instant.now())) - .build() -} - -private fun handleQuery( - context: PelletHTTPRouteContext -): HTTPRouteResponse { - val rawQueries = context.firstQueryParameter("queries").getOrNull() - val queries = (rawQueries?.toIntOrNull() ?: 1).coerceIn(1, 500) - val worlds = (1 .. queries) - .map { - repository.fetchWorld() - } - return HTTPRouteResponse.Builder() - .statusCode(200) - .jsonEntity(jsonEncoder, worlds) - .header("Server", "pellet") - .header("Date", dateFormatter.format(Instant.now())) - .build() -} - -private fun handleUpdates( - context: PelletHTTPRouteContext -): HTTPRouteResponse { - val rawQueries = context.firstQueryParameter("queries").getOrNull() - val queries = (rawQueries?.toIntOrNull() ?: 1).coerceIn(1, 500) - val worlds = (1 .. queries) - .map { - repository.fetchWorld() - } - val newWorlds = worlds.map { - it.copy( - randomNumber = ThreadLocalRandom.current().nextInt(1, 10001) - ) - } - repository.updateWorlds(newWorlds) - return HTTPRouteResponse.Builder() - .statusCode(200) - .jsonEntity(jsonEncoder, newWorlds) - .header("Server", "pellet") - .header("Date", dateFormatter.format(Instant.now())) - .build() -} - -private fun handleFortunes( - context: PelletHTTPRouteContext -): HTTPRouteResponse { - val newFortune = Fortune(0, "Additional fortune added at request time.") - val fortunes = repository.fetchFortunes().toMutableList() - fortunes.add(newFortune) - fortunes.sortBy { it.message } - val template = views.fortunes.template(fortunes) - .render(StringBuilderOutput.FACTORY) - .toString() - return HTTPRouteResponse.Builder() - .statusCode(200) - .entity(template, "text/html; charset=utf-8") - .header("Server", "pellet") - .header("Date", dateFormatter.format(Instant.now())) - .build() -} \ No newline at end of file diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/Fortune.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/Fortune.kt deleted file mode 100644 index 7dd31b0d5ab..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/Fortune.kt +++ /dev/null @@ -1,3 +0,0 @@ -package benchmark.data - -data class Fortune(val id: Int, val message: String) \ No newline at end of file diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/FortuneDAO.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/FortuneDAO.kt deleted file mode 100644 index 2413066f829..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/FortuneDAO.kt +++ /dev/null @@ -1,6 +0,0 @@ -package benchmark.data - -interface FortuneDAO { - - fun fetchFortunes(): List -} \ No newline at end of file diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/TFBRepository.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/TFBRepository.kt deleted file mode 100644 index 75357a462de..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/TFBRepository.kt +++ /dev/null @@ -1,67 +0,0 @@ -package benchmark.data - -import io.vertx.pgclient.PgBuilder -import io.vertx.pgclient.PgConnectOptions -import io.vertx.sqlclient.PoolOptions -import io.vertx.sqlclient.Tuple -import java.util.concurrent.ThreadLocalRandom - -class TFBRepository: WorldDAO, FortuneDAO { - - private val connectOptions = PgConnectOptions() - .setPort(5432) - .setHost("tfb-database") - .setDatabase("hello_world") - .setUser("benchmarkdbuser") - .setPassword("benchmarkdbpass") - .apply { - cachePreparedStatements = true - } - - private val poolOptions = PoolOptions() - private val client = PgBuilder.client() - .with(poolOptions) - .connectingTo(connectOptions) - .build() - - override fun fetchWorld(): WorldDTO { - val worldId = ThreadLocalRandom.current().nextInt(1, 10001) - val result = client - .preparedQuery("select id, randomNumber from world where id = $1") - .execute(Tuple.of(worldId)) - .toCompletionStage() - .toCompletableFuture() - .get() - val row = result.first() - return WorldDTO( - row.getInteger(0), - row.getInteger(1) - ) - } - - override fun updateWorlds(worlds: List) { - val batch = worlds.map { - Tuple.of(it.id, it.randomNumber) - } - client - .preparedQuery("update world set randomNumber = $1 where id = $2") - .executeBatch(batch) - .toCompletionStage() - .toCompletableFuture() - .get() - } - - override fun fetchFortunes(): List { - val results = client.preparedQuery("select id, message from fortune") - .execute() - .toCompletionStage() - .toCompletableFuture() - .get() - return results.map { - Fortune( - it.getInteger(0), - it.getString(1) - ) - } - } -} \ No newline at end of file diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDAO.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDAO.kt deleted file mode 100644 index fd91eb40d1a..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDAO.kt +++ /dev/null @@ -1,7 +0,0 @@ -package benchmark.data - -interface WorldDAO { - - fun fetchWorld(): WorldDTO - fun updateWorlds(worlds: List) -} \ No newline at end of file diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDTO.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDTO.kt deleted file mode 100644 index dc2cbb83657..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDTO.kt +++ /dev/null @@ -1,6 +0,0 @@ -package benchmark.data - -import kotlinx.serialization.Serializable - -@Serializable -data class WorldDTO(val id: Int, val randomNumber: Int) \ No newline at end of file diff --git a/frameworks/Kotlin/pellet/sample/src/main/resources/views/fortunes.rocker.html b/frameworks/Kotlin/pellet/sample/src/main/resources/views/fortunes.rocker.html deleted file mode 100644 index daacddbde35..00000000000 --- a/frameworks/Kotlin/pellet/sample/src/main/resources/views/fortunes.rocker.html +++ /dev/null @@ -1,15 +0,0 @@ -@import java.util.List -@import benchmark.data.Fortune -@args (List fortunes) - - - Fortunes - - - - @for (it: fortunes) { - - } -
idmessage
@it.getId()@it.getMessage()
- - diff --git a/frameworks/Kotlin/pronghorn/README.md b/frameworks/Kotlin/pronghorn/README.md deleted file mode 100644 index 93c9b29a856..00000000000 --- a/frameworks/Kotlin/pronghorn/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Pronghorn -This is the [Pronghorn Http Server](https://www.pronghorn.tech) portion of the [TechEmpower Framework Benchmarks](https://github.com/TechEmpower/FrameworkBenchmarks). - -## About -The Pronghorn HTTP Server is a low-level, high performance HTTP server written in [Kotlin](https://kotlinlang.org/). - -### Version -v0.1.2 : [https://github.com/pronghorn-tech/server/releases/tag/0.1.2](https://github.com/pronghorn-tech/server/releases/tag/0.1.2) - -## Test Types - -### Plaintext -url : `http://TFB-server:8080/plaintext` -source code : [TestServer.kt](src/main/kotlin/pronghorn/TestServer.kt) - -### Json Serialization -url : `http://TFB-server:8080/json` -source code : [JsonHandler.kt](src/main/kotlin/pronghorn/handlers/JsonHandler.kt) - -### Single Query -url : `http://TFB-server:8080/db` -source code : [MongoDBRequestSingleHandler.kt](src/main/kotlin/pronghorn/handlers/MongoDBRequestSingleHandler.kt) - -### Multiple Query -url : `http://TFB-server:8080/queries` -source code : [MongoDBRequestMultiHandler.kt](src/main/kotlin/pronghorn/handlers/MongoDBRequestMultiHandler.kt) - -### Data Updates -url : `http://TFB-server:8080/updates` -source code : [MongoDBRequestUpdatesHandler.kt](src/main/kotlin/pronghorn/handlers/MongoDBRequestUpdatesHandler.kt) - -### Fortunes -url : `http://TFB-server:8080/fortunes` -source code : [MongoDBRequestFortunesHandler.kt](src/main/kotlin/pronghorn/handlers/MongoDBRequestFortunesHandler.kt) - -## Additional Dependencies - -### Pronghorn Plugins -Pronghorn is by default a zero dependency library, but for the purpose of benchmarking these tests utilize three Pronghorn plugins for performance and logging : -* [JCTools Collections Plugin](https://github.com/pronghorn-tech/plugin-collections-jctools) - performance -* [OpenHFT Hashing Plugin](https://github.com/pronghorn-tech/plugin-hashing-openhft) - performance -* [SLF4J Logging Plugin](https://github.com/pronghorn-tech/plugin-logging-slf4j) - logging - -Additionally, database driven tests utilize the [Pronghorn MongoDB Driver Stream](https://github.com/pronghorn-tech/mongodb-driver-stream) which implements the MongoDB Driver's Stream interface via the [Pronghorn Coroutine Framework](https://github.com/pronghorn-tech/coroutines). This utilizes the cooperative nature of concurrency in Pronghorn to enable efficient multiplexing of database communication. - -### Third-Party Libraries -Beyond the Pronghorn plugins above, these tests utilize several third party libraries. - -#### JsonIter -Tests requiring json encoding utilize the [jsoniter](http://jsoniter.com/) library, as well as the [Javassist](http://jboss-javassist.github.io/javassist/) library for improved performance of jsoniter. - -#### MongoDB Async Driver -Database tests depend on the [async MongoDB driver](https://github.com/mongodb/mongo-java-driver/tree/master/driver-async). - -#### HTTL -The Fortunes test utilizes the [httl library](http://httl.github.io/en/) as the template engine. - -## Contact -For additional information, help, or corrections concerning Pronghorn or these tests contact info [at] pronghorn.tech diff --git a/frameworks/Kotlin/pronghorn/benchmark_config.json b/frameworks/Kotlin/pronghorn/benchmark_config.json deleted file mode 100644 index 25d32506609..00000000000 --- a/frameworks/Kotlin/pronghorn/benchmark_config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "framework": "pronghorn", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MongoDB", - "framework": "None", - "language": "Kotlin", - "flavor": "None", - "orm": "Raw", - "platform": "Pronghorn", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Pronghorn", - "notes": "", - "versus": "", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Kotlin/pronghorn/build.gradle b/frameworks/Kotlin/pronghorn/build.gradle deleted file mode 100644 index 2f99c271b12..00000000000 --- a/frameworks/Kotlin/pronghorn/build.gradle +++ /dev/null @@ -1,52 +0,0 @@ -group 'pronghorn' -version '0.1.0' - -buildscript { - ext { - pronghornVersion = '0.1.3' - kotlinVersion = '1.2.31' - } - - repositories { - jcenter() - } - - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - } -} - -apply plugin: 'kotlin' -apply plugin: 'application' - -mainClassName = "pronghorn.TestServerKt" - -applicationDefaultJvmArgs = ['-server', '-XX:+AggressiveOpts'] - -repositories { - mavenCentral() -} - -kotlin { - experimental { - coroutines 'enable' - } -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" - - compile 'ch.qos.logback:logback-classic:1.2.3' - - compile 'com.jsoniter:jsoniter:0.9.18' // json encoding library - compile 'org.javassist:javassist:3.22.0-GA' // needed for faster json encoding mode - compile 'org.mongodb:mongodb-driver-async:3.5.0' // async MongoDB driver - compile 'com.github.httl:httl:1.0.11' // simple template engine - - compile "tech.pronghorn:server:$pronghornVersion" - compile "tech.pronghorn:plugin-collections-jctools:$pronghornVersion" - compile "tech.pronghorn:plugin-hashing-openhft:$pronghornVersion" - compile "tech.pronghorn:plugin-logging-slf4j:$pronghornVersion" - compile "tech.pronghorn:mongodb-driver-stream:$pronghornVersion" -} diff --git a/frameworks/Kotlin/pronghorn/config.toml b/frameworks/Kotlin/pronghorn/config.toml deleted file mode 100644 index 0055eb6a69f..00000000000 --- a/frameworks/Kotlin/pronghorn/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "pronghorn" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Platform" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Pronghorn" -webserver = "None" -versus = "" diff --git a/frameworks/Kotlin/pronghorn/pronghorn.dockerfile b/frameworks/Kotlin/pronghorn/pronghorn.dockerfile deleted file mode 100644 index 1c957c351cc..00000000000 --- a/frameworks/Kotlin/pronghorn/pronghorn.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM gradle:4.7.0-jdk10 -USER root -WORKDIR /pronghorn -COPY build.gradle build.gradle -COPY settings.gradle settings.gradle -COPY src src - -EXPOSE 8080 - -CMD ["gradle", "--no-daemon", "run"] diff --git a/frameworks/Kotlin/pronghorn/settings.gradle b/frameworks/Kotlin/pronghorn/settings.gradle deleted file mode 100644 index 1a6e15ba157..00000000000 --- a/frameworks/Kotlin/pronghorn/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'pronghorn' diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/TestServer.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/TestServer.kt deleted file mode 100644 index 5b5fc7fe0a7..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/TestServer.kt +++ /dev/null @@ -1,29 +0,0 @@ -package pronghorn - -import ch.qos.logback.classic.Level -import com.jsoniter.output.EncodingMode -import com.jsoniter.output.JsonStream -import pronghorn.handlers.* -import pronghorn.utils.TestConfig -import pronghorn.utils.setLibraryLogging -import tech.pronghorn.http.HttpResponses -import tech.pronghorn.http.protocol.CommonContentTypes -import tech.pronghorn.server.HttpServer -import tech.pronghorn.server.requesthandlers.StaticHttpRequestHandler - -fun main(args: Array) { - JsonStream.setMode(EncodingMode.DYNAMIC_MODE) // enable faster Json encoding mode - setLibraryLogging(Level.WARN) // minimize logging from chatty libraries - - val helloWorldResponse = HttpResponses.OK("Hello, World!", CommonContentTypes.TextPlain) - val helloWorldHandler = StaticHttpRequestHandler(helloWorldResponse) - - val server = HttpServer(TestConfig.listenHost, TestConfig.listenPort) - server.registerUrlHandler("/plaintext", helloWorldHandler) - server.registerUrlHandlerGenerator("/json", { JsonHandler() }) - server.registerUrlHandlerGenerator("/db", { worker -> MongoDBRequestSingleHandler(worker) }) - server.registerUrlHandlerGenerator("/queries", { worker -> MongoDBRequestMultiHandler(worker) }) - server.registerUrlHandlerGenerator("/fortunes", { worker -> MongoDBRequestFortunesHandler(worker) }) - server.registerUrlHandlerGenerator("/updates", { worker -> MongoDBRequestUpdatesHandler(worker) }) - server.start() -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/JsonHandler.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/JsonHandler.kt deleted file mode 100644 index 40dfad25815..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/JsonHandler.kt +++ /dev/null @@ -1,20 +0,0 @@ -package pronghorn.handlers - -import com.jsoniter.output.JsonStream -import pronghorn.utils.JsonSupport -import tech.pronghorn.http.* -import tech.pronghorn.http.protocol.CommonContentTypes -import tech.pronghorn.server.requesthandlers.DirectHttpRequestHandler -import java.io.ByteArrayOutputStream - -data class JsonExample(val message: String) - -class JsonHandler: DirectHttpRequestHandler(), JsonSupport { - override val outputStream = ByteArrayOutputStream() - override val stream = JsonStream(outputStream, 32) - - override fun handleDirect(exchange: HttpExchange): HttpResponse { - val example = JsonExample("Hello, World!") - return HttpResponses.OK(toJson(example), CommonContentTypes.ApplicationJson) - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestFortunesHandler.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestFortunesHandler.kt deleted file mode 100644 index a8ed9729511..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestFortunesHandler.kt +++ /dev/null @@ -1,24 +0,0 @@ -package pronghorn.handlers - -import httl.Engine -import pronghorn.types.Fortune -import pronghorn.utils.MongoDBHandlerHelpers -import tech.pronghorn.http.* -import tech.pronghorn.http.protocol.CommonContentTypes -import tech.pronghorn.server.HttpServerWorker -import java.io.ByteArrayOutputStream - -class MongoDBRequestFortunesHandler(worker: HttpServerWorker) : MongoDBHandlerHelpers(worker) { - private val collection = getFortunesCollection() - private val engine = Engine.getEngine() - private val template = engine.getTemplate("/fortunes.httl") - private val output = ByteArrayOutputStream() - - suspend override fun handle(exchange: HttpExchange): HttpResponse { - val fortunes = findFortunes(collection) - fortunes.add(Fortune(0, "Additional fortune added at request time.")) - output.reset() - template.render(mapOf("fortunes" to fortunes), output) - return HttpResponses.OK(output.toByteArray(), CommonContentTypes.TextHtml, Charsets.UTF_8) - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestMultiHandler.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestMultiHandler.kt deleted file mode 100644 index 347f02bde20..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestMultiHandler.kt +++ /dev/null @@ -1,22 +0,0 @@ -package pronghorn.handlers - -import pronghorn.types.World -import pronghorn.utils.JsonSupport -import pronghorn.utils.MongoDBHandlerHelpers -import tech.pronghorn.coroutines.awaitable.InternalFuture -import tech.pronghorn.coroutines.awaitable.await -import tech.pronghorn.http.* -import tech.pronghorn.http.protocol.CommonContentTypes -import tech.pronghorn.server.HttpServerWorker - -class MongoDBRequestMultiHandler(worker: HttpServerWorker) : MongoDBHandlerHelpers(worker), JsonSupport { - private val collection = getWorldCollection() - - suspend override fun handle(exchange: HttpExchange): HttpResponse { - val future = InternalFuture>() - val worldCount = getQueryCount(exchange) - findWorlds(collection, future.promise(), worldCount) - val results = await(future) - return HttpResponses.OK(toJson(results), CommonContentTypes.ApplicationJson) - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestSingleHandler.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestSingleHandler.kt deleted file mode 100644 index 2aaaca95a1e..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestSingleHandler.kt +++ /dev/null @@ -1,15 +0,0 @@ -package pronghorn.handlers - -import pronghorn.utils.MongoDBHandlerHelpers -import tech.pronghorn.http.* -import tech.pronghorn.http.protocol.CommonContentTypes -import tech.pronghorn.server.HttpServerWorker - -class MongoDBRequestSingleHandler(worker: HttpServerWorker) : MongoDBHandlerHelpers(worker) { - private val collection = getWorldCollection() - - suspend override fun handle(exchange: HttpExchange): HttpResponse { - val world = findWorld(collection) - return HttpResponses.OK(toJson(world), CommonContentTypes.ApplicationJson) - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestUpdatesHandler.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestUpdatesHandler.kt deleted file mode 100644 index 24f6fc81b6a..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/handlers/MongoDBRequestUpdatesHandler.kt +++ /dev/null @@ -1,23 +0,0 @@ -package pronghorn.handlers - -import pronghorn.types.World -import pronghorn.utils.MongoDBHandlerHelpers -import tech.pronghorn.coroutines.awaitable.InternalFuture -import tech.pronghorn.coroutines.awaitable.await -import tech.pronghorn.http.* -import tech.pronghorn.http.protocol.CommonContentTypes -import tech.pronghorn.server.HttpServerWorker - -class MongoDBRequestUpdatesHandler(worker: HttpServerWorker) : MongoDBHandlerHelpers(worker) { - private val collection = getWorldCollection() - - suspend override fun handle(exchange: HttpExchange): HttpResponse { - val future = InternalFuture>() - val worldCount = getQueryCount(exchange) - findWorlds(collection, future.promise(), worldCount) - val results = await(future) - results.forEach { world -> world.randomNumber = random.nextInt(10000) + 1 } - writeWorlds(collection, results) - return HttpResponses.OK(toJson(results), CommonContentTypes.ApplicationJson) - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/Fortune.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/Fortune.kt deleted file mode 100644 index 8e1bfcb305b..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/Fortune.kt +++ /dev/null @@ -1,6 +0,0 @@ -package pronghorn.types - -class Fortune(val id: Int, - val message: String): Comparable { - override fun compareTo(other: Fortune): Int = message.compareTo(other.message) -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/World.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/World.kt deleted file mode 100644 index f97b500193b..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/World.kt +++ /dev/null @@ -1,4 +0,0 @@ -package pronghorn.types - -class World(val id: Int, - var randomNumber: Int) diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/codecs/FortuneCodec.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/codecs/FortuneCodec.kt deleted file mode 100644 index 4158ade8515..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/codecs/FortuneCodec.kt +++ /dev/null @@ -1,36 +0,0 @@ -package pronghorn.types.codecs - -import org.bson.* -import org.bson.codecs.* -import pronghorn.types.Fortune - -object FortuneCodec : Codec { - private val fortuneClass = Fortune::class.java - - override fun encode(writer: BsonWriter, value: Fortune, encoderContext: EncoderContext) { - writer.writeStartDocument() - writer.writeInt32(value.id) - writer.writeString(value.message) - writer.writeEndDocument() - } - - override fun getEncoderClass(): Class = fortuneClass - - override fun decode(reader: BsonReader, decoderContext: DecoderContext): Fortune { - reader.readStartDocument() - reader.readBsonType() - reader.skipName() - val id = when(reader.currentBsonType) { - BsonType.DOUBLE -> reader.readDouble().toInt() - BsonType.INT32 -> reader.readInt32() - else -> throw Exception("Unexpected ID Type") - } - reader.readBsonType() - reader.skipName() - reader.skipValue() - val message = reader.readString("message") - val fortune = Fortune(id, message) - reader.readEndDocument() - return fortune - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/codecs/WorldCodec.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/codecs/WorldCodec.kt deleted file mode 100644 index f3afaea46d1..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/types/codecs/WorldCodec.kt +++ /dev/null @@ -1,42 +0,0 @@ -package pronghorn.types.codecs - -import org.bson.* -import org.bson.codecs.* -import pronghorn.types.World - -object WorldCodec: Codec { - private val worldClass = World::class.java - - override fun encode(writer: BsonWriter, value: World, encoderContext: EncoderContext) { - writer.writeStartDocument() - writer.writeInt32(value.id) - writer.writeInt32(value.randomNumber) - writer.writeEndDocument() - } - - override fun getEncoderClass(): Class = worldClass - - override fun decode(reader: BsonReader, decoderContext: DecoderContext): World { - reader.readStartDocument() - reader.readBsonType() - reader.skipName() - val id = when(reader.currentBsonType) { - BsonType.DOUBLE -> reader.readDouble().toInt() - BsonType.INT32 -> reader.readInt32() - else -> throw Exception("Unexpected ID Type") - } - reader.readBsonType() - reader.skipName() - reader.skipValue() - reader.readBsonType() - reader.skipName() - val randomNumber = when(reader.currentBsonType) { - BsonType.DOUBLE -> reader.readDouble().toInt() - BsonType.INT32 -> reader.readInt32() - else -> throw Exception("Unexpected randomNumber Type") - } - val world = World(id, randomNumber) - reader.readEndDocument() - return world - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/JsonSupport.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/JsonSupport.kt deleted file mode 100644 index 157e5d1acc5..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/JsonSupport.kt +++ /dev/null @@ -1,16 +0,0 @@ -package pronghorn.utils - -import com.jsoniter.output.JsonStream -import java.io.ByteArrayOutputStream - -interface JsonSupport { - val outputStream: ByteArrayOutputStream - val stream: JsonStream - - fun toJson(any: Any): ByteArray { - outputStream.reset() - stream.writeVal(any) - stream.flush() - return outputStream.toByteArray() - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/LoggingUtils.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/LoggingUtils.kt deleted file mode 100644 index f00d800d5fd..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/LoggingUtils.kt +++ /dev/null @@ -1,11 +0,0 @@ -package pronghorn.utils - -import ch.qos.logback.classic.Level -import ch.qos.logback.classic.LoggerContext -import org.slf4j.LoggerFactory - -fun setLibraryLogging(level: Level) { - val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext - loggerContext.getLogger("org.mongodb.driver").level = level - loggerContext.getLogger("httl").level = level -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/MongoDBClientAttachmentKey.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/MongoDBClientAttachmentKey.kt deleted file mode 100644 index 3056c4d90e0..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/MongoDBClientAttachmentKey.kt +++ /dev/null @@ -1,6 +0,0 @@ -package pronghorn.utils - -import com.mongodb.async.client.MongoClient -import tech.pronghorn.coroutines.core.WorkerAttachmentKey - -object MongoDBClientAttachmentKey : WorkerAttachmentKey diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/MongoDBHandlerHelpers.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/MongoDBHandlerHelpers.kt deleted file mode 100644 index c4d3cff61e2..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/MongoDBHandlerHelpers.kt +++ /dev/null @@ -1,155 +0,0 @@ -package pronghorn.utils - -import com.jsoniter.output.JsonStream -import com.mongodb.ServerAddress -import com.mongodb.async.client.* -import com.mongodb.client.model.Filters -import com.mongodb.client.model.UpdateOneModel -import com.mongodb.connection.ClusterSettings -import com.mongodb.connection.ConnectionPoolSettings -import org.bson.Document -import org.bson.codecs.configuration.CodecRegistries -import pronghorn.types.Fortune -import pronghorn.types.World -import pronghorn.types.codecs.FortuneCodec -import pronghorn.types.codecs.WorldCodec -import tech.pronghorn.coroutines.awaitable.InternalFuture -import tech.pronghorn.coroutines.awaitable.await -import tech.pronghorn.http.HttpExchange -import tech.pronghorn.mongodb.MultiplexMongoDBStreamFactoryFactory -import tech.pronghorn.server.HttpServerWorker -import tech.pronghorn.server.requesthandlers.SuspendableHttpRequestHandler -import java.io.ByteArrayOutputStream -import java.util.SplittableRandom -import java.util.TreeSet - -private val queriesBytes = "queries".toByteArray(Charsets.US_ASCII) - -abstract class MongoDBHandlerHelpers(worker: HttpServerWorker) : SuspendableHttpRequestHandler(), JsonSupport { - private val mongoClient = worker.getOrPutAttachment(MongoDBClientAttachmentKey, { createMongoClient(worker) }) - protected val random = SplittableRandom() - override final val outputStream = ByteArrayOutputStream() - override final val stream = JsonStream(outputStream, 32) - - protected fun getWorldCollection(): MongoCollection { - return mongoClient - .getDatabase(TestConfig.dbName) - .getCollection(TestConfig.worldCollectionName) - .withDocumentClass(World::class.java) - } - - protected fun getFortunesCollection(): MongoCollection { - return mongoClient - .getDatabase(TestConfig.dbName) - .getCollection(TestConfig.fortunesCollectionName) - .withDocumentClass(Fortune::class.java) - } - - private fun createMongoClient(worker: HttpServerWorker): MongoClient { - val poolSettings = ConnectionPoolSettings.builder() - .minSize(1) - .maxSize(Int.MAX_VALUE) // connections are multiplexed via Pronghorn Stream, so max size is irrelevant - .maxWaitQueueSize(0) - .build() - - val clusterSettings = ClusterSettings.builder() - .hosts(listOf(ServerAddress(TestConfig.dbHost, TestConfig.dbPort))) - .build() - - val multiplexedFactory = MultiplexMongoDBStreamFactoryFactory(worker) - - val codecRegistry = CodecRegistries.fromRegistries( - MongoClients.getDefaultCodecRegistry(), - CodecRegistries.fromCodecs(FortuneCodec, WorldCodec) - ) - - val settings = MongoClientSettings.builder() - .clusterSettings(clusterSettings) - .connectionPoolSettings(poolSettings) - .streamFactoryFactory(multiplexedFactory) - .codecRegistry(codecRegistry) - .build() - - val client = MongoClients.create(settings) - worker.registerShutdownMethod { - client.close() - } - return client - } - - protected fun getQueryCount(exchange: HttpExchange): Int { - return Math.max(1, Math.min(500, exchange.requestUrl.getQueryParamAsInt(queriesBytes) ?: 1)) - } - - suspend protected fun findWorld(collection: MongoCollection): World { - val future = InternalFuture() - val promise = future.promise() - val id = random.nextInt(10000) + 1 - collection.find(Document("_id", id)).first { world, ex -> - when { - world != null -> promise.complete(world) - ex != null -> promise.completeExceptionally(ex) - else -> promise.completeExceptionally(Exception("Missing document.")) - } - } - return await(future) - } - - @Suppress("UNCHECKED_CAST") - protected fun findWorlds(collection: MongoCollection, - promise: InternalFuture.InternalPromise>, - count: Int, - results: Array = arrayOfNulls(count)) { - val id = count - val searchDocument = Document("_id", id) - collection.find(searchDocument).first { world, ex -> - when { - world != null -> { - results[count - 1] = world - if (count == 1) { - promise.complete(results as Array) - } - else { - findWorlds(collection, promise, count - 1, results) - } - } - ex != null -> promise.completeExceptionally(ex) - else -> promise.completeExceptionally(Exception("Missing document.")) - } - } - } - - protected suspend fun findFortunes(collection: MongoCollection): TreeSet { - val future = InternalFuture() - val promise = future.promise() - val fortunes = TreeSet() - - collection.find().into(fortunes, { _, _ -> promise.complete(Unit) }) - - await(future) - return fortunes - } - - protected suspend fun writeWorlds(collection: MongoCollection, - results: Array) { - val updateFuture = InternalFuture() - val updatePromise = updateFuture.promise() - - val updates = results.map { result -> - UpdateOneModel( - Filters.eq("_id", result.id), - Document("\$set", Document("randomNumber", result.randomNumber)) - ) - } - - collection.bulkWrite(updates, { result, ex -> - when { - result != null -> updatePromise.complete(Unit) - ex != null -> updatePromise.completeExceptionally(ex) - else -> updatePromise.completeExceptionally(Exception("Unexpected update failure.")) - } - }) - - await(updateFuture) - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/TestConfig.kt b/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/TestConfig.kt deleted file mode 100644 index 09ef4fdeefd..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/kotlin/pronghorn/utils/TestConfig.kt +++ /dev/null @@ -1,35 +0,0 @@ -package pronghorn.utils - -import tech.pronghorn.util.ignoreException -import java.util.Properties - -object TestConfig { - private val properties = parsePropertiesConfig() - val listenHost = properties.getProperty("listenHost", "0.0.0.0") - val listenPort = getIntProperty("listenPort", 8080) - val dbHost = properties.getProperty("dbHost", "tfb-database") - val dbPort = getIntProperty("dbPort", 27017) - val dbName = properties.getProperty("dbName", "hello_world") - val fortunesCollectionName = properties.getProperty("fortunesCollectionName", "fortune") - val worldCollectionName = properties.getProperty("worldCollectionName", "world") - - private fun getIntProperty(key: String, - default: Int): Int { - val result = properties.getProperty(key) - return when (result) { - null -> default - else -> result.toIntOrNull() ?: default - } - } - - private fun parsePropertiesConfig(): Properties { - val properties = Properties() - ignoreException { - val stream = javaClass.classLoader.getResource("benchmark.properties")?.openStream() - if (stream != null) { - properties.load(stream) - } - } - return properties - } -} diff --git a/frameworks/Kotlin/pronghorn/src/main/resources/benchmark.properties b/frameworks/Kotlin/pronghorn/src/main/resources/benchmark.properties deleted file mode 100644 index 0e62ae9b53c..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/resources/benchmark.properties +++ /dev/null @@ -1,7 +0,0 @@ -listenHost=0.0.0.0 -listenPort=8080 -dbHost=tfb-database -dbPort=27017 -dbName=hello_world -fortunesCollectionName=fortune -worldCollectionName=world diff --git a/frameworks/Kotlin/pronghorn/src/main/resources/fortunes.httl b/frameworks/Kotlin/pronghorn/src/main/resources/fortunes.httl deleted file mode 100644 index de8d01ae0e9..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/resources/fortunes.httl +++ /dev/null @@ -1 +0,0 @@ -Fortunes
idmessage
${fortune.id}${fortune.message}
diff --git a/frameworks/Kotlin/pronghorn/src/main/resources/httl.properties b/frameworks/Kotlin/pronghorn/src/main/resources/httl.properties deleted file mode 100644 index 33cd652a032..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/resources/httl.properties +++ /dev/null @@ -1,5 +0,0 @@ -import.packages+=pronghorn.types -input.encoding=UTF-8 -output.encoding=UTF-8 -reloadable=false -precompiled=false diff --git a/frameworks/Kotlin/pronghorn/src/main/resources/logback.xml b/frameworks/Kotlin/pronghorn/src/main/resources/logback.xml deleted file mode 100644 index f8a0bcedfc3..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/resources/logback.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - diff --git a/frameworks/Kotlin/pronghorn/src/main/resources/pronghorn.properties b/frameworks/Kotlin/pronghorn/src/main/resources/pronghorn.properties deleted file mode 100644 index 030160c0a3c..00000000000 --- a/frameworks/Kotlin/pronghorn/src/main/resources/pronghorn.properties +++ /dev/null @@ -1,6 +0,0 @@ -pronghorn.plugins.LoggingPlugin = tech.pronghorn.plugins.Slf4jLoggingPlugin -pronghorn.plugins.SpscQueuePlugin = tech.pronghorn.plugins.JCToolsSpscQueuePlugin -pronghorn.plugins.MpscQueuePlugin = tech.pronghorn.plugins.JCToolsMpscQueuePlugin -pronghorn.plugins.ConcurrentMapPlugin = tech.pronghorn.plugins.JCToolsConcurrentMapPlugin -pronghorn.plugins.ConcurrentSetPlugin = tech.pronghorn.plugins.JCToolsConcurrentSetPlugin -pronghorn.plugins.ArrayHasherPlugin = tech.pronghorn.plugins.OpenHFTArrayHasherPlugin diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts index 973bf6d8116..3e7b816e33c 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts @@ -1,37 +1,39 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED +import org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED +import org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - kotlin("jvm") version "2.0.21" + kotlin("jvm") version "2.3.0" application - id("nu.studer.rocker") version "3.0.4" - id("com.gradleup.shadow") version "8.3.4" + id("nu.studer.rocker") version "3.2" + id("com.gradleup.shadow") version "9.3.0" } group = "io.vertx" -version = "4.3.8" // 4.5.10 is available, but this is not updated to be kept consistent with the "vert-web" portion +version = "5.0.5" // kept consistent with the "vert-web" portion repositories { mavenCentral() } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") implementation(platform("io.vertx:vertx-stack-depchain:$version")) implementation("io.vertx:vertx-core") - implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.14.2") // 2.18.1 is available, but this is not updated to be kept consistent with the "vert-web" portion + implementation("io.vertx:vertx-launcher-application") + implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.19.0") // kept consistent with the "vert-web" portion implementation("io.vertx:vertx-web") implementation("io.vertx:vertx-pg-client") implementation("io.vertx:vertx-web-templ-rocker") - runtimeOnly("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") - // not used to make the project consistent with the "vert-web" portion - /* - runtimeOnly("io.vertx:vertx-io_uring-incubator") - runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") - */ + //runtimeOnly("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + runtimeOnly("io.netty", "netty-transport-native-io_uring", classifier = "linux-x86_64") implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") } @@ -41,18 +43,19 @@ rocker { create("main") { templateDir.set(file("src/main/resources")) optimize.set(true) - javaVersion.set("17") // kept consistent with the "vert-web" portion + javaVersion.set("25") // kept consistent with the "vert-web" portion } } } -kotlin.jvmToolchain(17) // kept consistent with the "vert-web" portion +kotlin.jvmToolchain(25) // kept consistent with the "vert-web" portion // content below copied from the project generated by the app generator val mainVerticleName = "io.vertx.benchmark.App" -val launcherClassName = "io.vertx.core.Launcher" +val launcherClassName = "io.vertx.launcher.application.VertxApplication" + application { mainClass.set(launcherClassName) } @@ -65,14 +68,6 @@ tasks.withType { mergeServiceFiles() } -val watchForChange = "src/**/*" -val doOnChange = "${projectDir}/gradlew classes" tasks.withType { - args = listOf( - "run", - mainVerticleName, - "--redeploy=$watchForChange", - "--launcher-class=$launcherClassName", - "--on-redeploy=$doOnChange" - ) + args = listOf(mainVerticleName) } diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d..f8e1ee3125f 100644 Binary files a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties index 79eb9d003fe..4eac4a84cc3 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew index f5feea6d6b1..adff685a034 100755 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -206,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat index 9d21a21834d..c4bdd3ab8e3 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/src/main/kotlin/io/vertx/benchmark/App.kt b/frameworks/Kotlin/vertx-web-kotlin-coroutines/src/main/kotlin/io/vertx/benchmark/App.kt index cfb47cd1fa6..142a457f548 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/src/main/kotlin/io/vertx/benchmark/App.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/src/main/kotlin/io/vertx/benchmark/App.kt @@ -14,7 +14,7 @@ import io.vertx.ext.web.Router import io.vertx.ext.web.RoutingContext import io.vertx.ext.web.templ.rocker.RockerTemplateEngine import io.vertx.kotlin.coroutines.CoroutineVerticle -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait import io.vertx.kotlin.pgclient.pgConnectOptionsOf import io.vertx.pgclient.PgConnection import io.vertx.sqlclient.Tuple @@ -31,15 +31,14 @@ class App : CoroutineVerticle() { companion object { init { DatabindCodec.mapper().registerModule(BlackbirdModule()) - DatabindCodec.prettyMapper().registerModule(BlackbirdModule()) } private const val SERVER = "vertx-web" // for PgClientBenchmark only - private const val UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2" - private const val SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1" - private const val SELECT_FORTUNE = "SELECT id, message from FORTUNE" + private const val UPDATE_WORLD = "UPDATE world SET randomnumber = $1 WHERE id = $2" + private const val SELECT_WORLD = "SELECT id, randomnumber FROM world WHERE id = $1" + private const val SELECT_FORTUNE = "SELECT id, message FROM fortune" } inline fun Route.coroutineHandlerUnconfined(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route = @@ -70,7 +69,7 @@ class App : CoroutineVerticle() { return PgClientBenchmark( try { - PgConnection.connect(vertx, options).await() + PgConnection.connect(vertx, options).coAwait() } catch (e: UnknownHostException) { null }, @@ -91,7 +90,7 @@ class App : CoroutineVerticle() { client!! .preparedQuery(SELECT_WORLD) .execute(Tuple.of(randomWorld())) - .await() + .coAwait() } catch (t: Throwable) { // adapted from the Java code and kept, though I don't see the purpose of this t.printStackTrace() @@ -103,7 +102,7 @@ class App : CoroutineVerticle() { ctx.response() .setStatusCode(404) .end() - .await() + .coAwait() return } val row = resultSet.next() @@ -112,7 +111,7 @@ class App : CoroutineVerticle() { .putHeader(HttpHeaders.DATE, date) .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") .end(Json.encodeToBuffer(World(row.getInteger(0), row.getInteger(1)))) - .await() + .coAwait() } suspend fun queriesHandler(ctx: RoutingContext) { @@ -122,7 +121,7 @@ class App : CoroutineVerticle() { val cnt = intArrayOf(0) List(queries) { async { - val result = `try` { client!!.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).await() } + val result = `try` { client!!.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld())).coAwait() } if (!failed[0]) { if (result is Try.Failure) { @@ -142,7 +141,7 @@ class App : CoroutineVerticle() { .putHeader(HttpHeaders.DATE, date) .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") .end(Json.encodeToBuffer(worlds)) - .await() + .coAwait() } } } @@ -151,7 +150,7 @@ class App : CoroutineVerticle() { } suspend fun fortunesHandler(ctx: RoutingContext) { - val result = client!!.preparedQuery(SELECT_FORTUNE).execute().await() + val result = client!!.preparedQuery(SELECT_FORTUNE).execute().coAwait() val resultSet = result.iterator() if (!resultSet.hasNext()) { @@ -168,13 +167,13 @@ class App : CoroutineVerticle() { ctx.put("fortunes", fortunes) // and now delegate to the engine to render it. - val result2 = engine.render(ctx.data(), "templates/Fortunes.rocker.html").await() + val result2 = engine.render(ctx.data(), "templates/Fortunes.rocker.html").coAwait() ctx.response() .putHeader(HttpHeaders.SERVER, SERVER) .putHeader(HttpHeaders.DATE, date) .putHeader(HttpHeaders.CONTENT_TYPE, "text/html; charset=UTF-8") .end(result2) - .await() + .coAwait() } suspend fun updateHandler(ctx: RoutingContext) { @@ -185,7 +184,7 @@ class App : CoroutineVerticle() { List(worlds.size) { val id = randomWorld() async { - val r2 = `try` { client!!.preparedQuery(SELECT_WORLD).execute(Tuple.of(id)).await() } + val r2 = `try` { client!!.preparedQuery(SELECT_WORLD).execute(Tuple.of(id)).coAwait() } if (!failed[0]) { if (r2 is Try.Failure) { @@ -205,13 +204,13 @@ class App : CoroutineVerticle() { ctx.checkedRun { client!!.preparedQuery(UPDATE_WORLD) .executeBatch(batch) - .await() + .coAwait() ctx.response() .putHeader(HttpHeaders.SERVER, SERVER) .putHeader(HttpHeaders.DATE, date) .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") .end(Json.encodeToBuffer(worlds)) - .await() + .coAwait() } } } @@ -240,7 +239,7 @@ class App : CoroutineVerticle() { .putHeader(HttpHeaders.DATE, date) .putHeader(HttpHeaders.CONTENT_TYPE, "application/json") .end(Json.encodeToBuffer(Message("Hello, World!"))) - .await() + .coAwait() } /* @@ -281,10 +280,10 @@ class App : CoroutineVerticle() { .putHeader(HttpHeaders.DATE, date) .putHeader(HttpHeaders.CONTENT_TYPE, "text/plain") .end("Hello, World!") - .await() + .coAwait() } try { - vertx.createHttpServer().requestHandler(app).listen(8080).await() + vertx.createHttpServer().requestHandler(app).listen(8080).coAwait() } catch (t: Throwable) { t.printStackTrace() exitProcess(1) diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile index dfcc87cb4bb..ba823f5d56d 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.10.2-jdk17 as gradle +FROM gradle:9.2.1-jdk25 as gradle WORKDIR /vertx-web-kotlin-coroutines COPY src src COPY build.gradle.kts build.gradle.kts @@ -24,7 +24,7 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -jar \ - build/libs/vertx-web-kotlin-coroutines-benchmark-4.3.8-fat.jar \ + build/libs/vertx-web-kotlin-coroutines-benchmark-5.0.5-fat.jar \ --instances \ `grep --count ^processor /proc/cpuinfo` \ --conf \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile index dfcc87cb4bb..ba823f5d56d 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/vertx-web-kotlin-coroutines.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.10.2-jdk17 as gradle +FROM gradle:9.2.1-jdk25 as gradle WORKDIR /vertx-web-kotlin-coroutines COPY src src COPY build.gradle.kts build.gradle.kts @@ -24,7 +24,7 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -jar \ - build/libs/vertx-web-kotlin-coroutines-benchmark-4.3.8-fat.jar \ + build/libs/vertx-web-kotlin-coroutines-benchmark-5.0.5-fat.jar \ --instances \ `grep --count ^processor /proc/cpuinfo` \ --conf \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitignore b/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitignore new file mode 100644 index 00000000000..2f36f26d381 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitignore @@ -0,0 +1 @@ +libs/ \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md index 2cb792746e2..9c62481d159 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md @@ -31,8 +31,7 @@ http://localhost:8080/query?queries= http://localhost:8080/update?queries= - -Testing: +## Testing: ```shell ../../../tfb \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json index 0625b6406be..2115f75a507 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "vertx-web-kotlin-dsljson", + "maintainers": ["awmcc90"], "tests": [ { "default": { @@ -25,6 +26,7 @@ "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Micro", diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts index 03517f3a9a7..6fc476870ac 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts @@ -1,9 +1,15 @@ +import java.net.URI +import java.nio.charset.StandardCharsets +import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion +import org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.kapt) alias(libs.plugins.shadow) + alias(libs.plugins.rocker.nu) application } @@ -19,13 +25,16 @@ java { kotlin { compilerOptions { jvmTarget = JvmTarget.JVM_25 - apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3) - languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_3) - freeCompilerArgs.addAll(listOf( - "-Xjvm-default=all", + apiVersion.set(KotlinVersion.KOTLIN_2_3) + languageVersion.set(KotlinVersion.KOTLIN_2_3) + jvmDefault = JvmDefaultMode.ENABLE + freeCompilerArgs.addAll( "-Xlambdas=indy", - "-Xjdk-release=25" - )) + "-Xstring-concat=indy-with-constants", + "-Xno-call-assertions", + "-Xno-param-assertions", + "-Xno-receiver-assertions", + ) } jvmToolchain(25) } @@ -34,6 +43,8 @@ application { mainClass = "com.example.starter.AppKt" } +val patchedNettyJar = file("libs/netty-patched.jar") + dependencies { // Kotlin implementation(libs.kotlin.stdlib) @@ -46,13 +57,12 @@ dependencies { implementation(libs.vertx.pg.client) implementation(libs.vertx.lang.kotlin) implementation(libs.vertx.lang.kotlin.coroutines) - implementation(libs.vertx.micrometer) - - // Micrometer - implementation(libs.micrometer.registry.prometheus) // Netty - implementation(platform(libs.netty.bom)) + implementation(files(patchedNettyJar)) + implementation(platform(libs.netty.bom)) { + exclude(group = "io.netty", module = "netty-transport-classes-io_uring") + } resolvePlatformSpecificNettyDependencies(libs.versions.netty.get()) .forEach { implementation(it) } @@ -62,12 +72,60 @@ dependencies { // Log4j implementation(libs.log4j.core) + kapt(libs.log4j.core) + implementation(libs.log4j.api) implementation(libs.log4j.api.kotlin) + + // Disruptor implementation(libs.disruptor) + + // Rocker + implementation(libs.rocker.runtime) + kapt(libs.rocker.compiler) +} + +rocker { + version = libs.versions.rocker.asProvider().get() + configurations { + create("main").apply { + javaVersion = "25" + templateDir = project.layout.projectDirectory.dir("src/main/resources/rocker") + outputDir = project.layout.buildDirectory.dir("generated/source/rocker") + targetCharset = StandardCharsets.UTF_8.name() + optimize = true + markAsGenerated = true + } + } +} + +val downloadPatchedNetty by tasks.registering { + outputs.file(patchedNettyJar) + doLast { + val uri = URI.create("https://github.com/awmcc90/netty/releases/download/4.2-patched/netty-transport-classes-io_uring-4.2.9.Final.jar") + logger.lifecycle("Downloading Patched Netty to ${patchedNettyJar.path}...") + patchedNettyJar.parentFile.mkdirs() + uri.toURL().openStream().use { input -> + patchedNettyJar.outputStream().use { output -> + input.copyTo(output) + } + } + } } tasks { + withType().configureEach { + dependsOn(downloadPatchedNetty) + } + + compileKotlin { + dependsOn(downloadPatchedNetty) + } + + compileJava { + dependsOn(downloadPatchedNetty) + } + register("server") { dependsOn(this@tasks.classes) @@ -77,21 +135,26 @@ tasks { jvmArgs = listOf( "-server", "--enable-native-access=ALL-UNNAMED", - "--add-opens=java.base/java.lang=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", + "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+DebugNonSafepoints", + "-XX:+EnableDynamicAgentLoading", + "-XX:+PreserveFramePointer", "-Xms2G", "-Xmx2G", + "-XX:MaxDirectMemorySize=6G", "-XX:+AlwaysPreTouch", "-XX:+UseParallelGC", "-XX:InitialCodeCacheSize=512m", "-XX:ReservedCodeCacheSize=512m", - "-XX:MaxInlineLevel=20", "-XX:+UseNUMA", - "-XX:-UseCodeCacheFlushing", - "-XX:AutoBoxCacheMax=10001", + "-XX:AutoBoxCacheMax=20000", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+DebugNonSafepoints", "-Djava.net.preferIPv4Stack=true", "-Dvertx.disableMetrics=true", "-Dvertx.disableWebsockets=true", @@ -103,14 +166,20 @@ tasks { "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.leakDetection.level=disabled", - "-Dio.netty.iouring.ringSize=4096", - "-Dio.netty.iouring.cqSize=8192", + "-Dio.netty.tryReflectionSetAccessible=true", + "-Dio.netty.iouring.ringSize=8192", + "-Dio.netty.iouring.cqSize=16384", "-Dtfb.type=basic", ) } shadowJar { + mainClass = application.mainClass.get() archiveClassifier = "fat" mergeServiceFiles() + entryCompression = ZipEntryCompression.STORED + + exclude("META-INF/versions/**/module-info.class") + exclude("module-info.class") } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt index 99d81bec357..55ca50c590b 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt @@ -54,5 +54,7 @@ fun resolvePlatformSpecificNettyDependencies(version: String) = when (CURRENT_SY "io.netty:netty-transport-native-kqueue:$version:osx-aarch_64", "io.netty:netty-resolver-dns-native-macos:$version:osx-aarch_64", ) - else -> throw IllegalStateException("Unsupported system: $CURRENT_SYSTEM_INFO") + else -> arrayOf( + "io.netty:netty-transport-native-io_uring:$version:linux-x86_64", + ) } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh index 6b8380b9308..a0c76b210f3 100755 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh @@ -58,11 +58,8 @@ java \ -Xms2G \ -Xmx2G \ -XX:+AlwaysPreTouch \ - -XX:+UseZGC \ - -XX:+ZUncommit \ + -XX:+UseParallelGC \ -XX:+DisableExplicitGC \ - -XX:+UseLargePages \ - -XX:+UseStringDeduplication \ -XX:+EnableDynamicAgentLoading \ -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ @@ -83,7 +80,7 @@ java \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.recycler.maxCapacity.default=0 \ -Dio.netty.maxDirectMemory=0 \ - "-Dtfb.hasDB=$HAS_DB" \ + "-Dtfb.type=basic" \ "-Dtfb.pgHostOverride=0.0.0.0" \ -jar "$JAR_PATH" & diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties index f97ebb7d334..762ba4008f7 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties @@ -1 +1,11 @@ +org.gradle.daemon=true org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configureondemand=true +org.gradle.jvmargs=-Xms2g -Xmx4g -XX:MaxMetaspaceSize=512m -XX:+UseParallelGC -Dfile.encoding=UTF-8 + +kotlin.incremental=true +kotlin.parallel.tasks.in.project=true +kotlin.daemon.jvmargs=-Xms256m -Xmx2g -XX:+UseParallelGC +kapt.incremental.apt=true +kapt.use.worker.api=true \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml index 42556c390c6..3e19ca7805b 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml @@ -1,13 +1,14 @@ [versions] -kotlin = "2.3.0-Beta2" +kotlin = "2.3.0" shadow = "9.2.2" -vertx = "5.0.5" -micrometer = "1.16.0" -netty = "4.2.7.Final" +vertx = "5.0.6" +netty = "4.2.9.Final" dsljson = "2.0.2" -log4j = "2.25.2" +log4j = "2.25.3" log4j-kotlin = "1.5.0" disruptor = "4.0.0" +rocker = "2.4.0" +rocker-nu = "3.2" [libraries] # Kotlin @@ -21,10 +22,6 @@ vertx-web = { module = "io.vertx:vertx-web" } vertx-pg-client = { module = "io.vertx:vertx-pg-client" } vertx-lang-kotlin = { module = "io.vertx:vertx-lang-kotlin" } vertx-lang-kotlin-coroutines = { module = "io.vertx:vertx-lang-kotlin-coroutines" } -vertx-micrometer = { module = "io.vertx:vertx-micrometer-metrics" } - -# Prometheus -micrometer-registry-prometheus = { module = "io.micrometer:micrometer-registry-prometheus", version.ref = "micrometer" } # Netty netty-bom = { module = "io.netty:netty-bom", version.ref = "netty" } @@ -38,7 +35,12 @@ log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4 log4j-api-kotlin = { module = "org.apache.logging.log4j:log4j-api-kotlin", version.ref = "log4j-kotlin" } disruptor = { module = "com.lmax:disruptor", version.ref = "disruptor" } +# Rocker +rocker-runtime = { module = "com.fizzed:rocker-runtime", version.ref = "rocker" } +rocker-compiler = { module = "com.fizzed:rocker-compiler", version.ref = "rocker" } + [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } +rocker-nu = { id = "nu.studer.rocker", version.ref = "rocker-nu" } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts index a9e579940ea..4d58d5a08b7 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts @@ -1,3 +1,5 @@ +rootProject.name = "vertx-web-kotlin-dsljson-benchmark" + pluginManagement { repositories { gradlePluginPortal() @@ -6,10 +8,7 @@ pluginManagement { } dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() } } - -rootProject.name = "vertx-web-kotlin-dsljson-benchmark" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt index 21b08c43611..575c8a254f9 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt @@ -7,8 +7,6 @@ import io.vertx.core.Vertx import io.vertx.kotlin.core.deploymentOptionsOf import io.vertx.kotlin.core.vertxOptionsOf import io.vertx.kotlin.coroutines.coAwait -import io.vertx.kotlin.micrometer.micrometerMetricsOptionsOf -import io.vertx.kotlin.micrometer.vertxPrometheusOptionsOf import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.runBlocking import org.apache.logging.log4j.kotlin.logger @@ -22,16 +20,6 @@ fun main(): Unit = runBlocking { preferNativeTransport = true, disableTCCL = true, blockedThreadCheckInterval = 60_000, - metricsOptions = if (Properties.METRICS_ENABLED) { - micrometerMetricsOptionsOf( - enabled = true, - jvmMetricsEnabled = true, - nettyMetricsEnabled = true, - prometheusOptions = vertxPrometheusOptionsOf( - enabled = true, - ), - ) - } else null ) ) @@ -58,6 +46,8 @@ fun main(): Unit = runBlocking { instances = Properties.EVENT_LOOP_POOL_SIZE, ) + LOGGER.info("Initializing Verticle: ${Properties.TYPE}") + val deployment = when (Properties.TYPE) { "basic" -> vertx.deployVerticle( BasicVerticle::class.java, diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt index 0a20956558e..fa6926d1ae3 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt @@ -39,7 +39,7 @@ class BasicVerticle : CoroutineVerticle() { logger.info("HTTP server started on port ${server.actualPort()}") } - companion object : Logging { + private companion object : Logging { private const val PLAINTEXT_PATH = "/plaintext" private const val JSON_PATH = "/json" } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt index 5d31eb03bc4..271cb625ad7 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt @@ -54,7 +54,7 @@ class PostgresVerticle : CoroutineVerticle() { logger.info("HTTP server started on port ${server.actualPort()}") } - companion object : Logging { + private companion object : Logging { private const val FORTUNES_PATH = "/fortunes" private const val DB_PATH = "/db" private const val QUERIES_PATH = "/queries" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt index c86ea244774..f1bd746de11 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt @@ -8,17 +8,12 @@ import com.example.starter.handlers.MessageHandler import com.example.starter.handlers.WorldHandler import com.example.starter.helpers.Properties import com.example.starter.utils.isConnectionReset -import io.micrometer.prometheusmetrics.PrometheusMeterRegistry -import io.vertx.core.Handler -import io.vertx.core.http.HttpHeaders.CONTENT_TYPE -import io.vertx.core.http.HttpServerRequest import io.vertx.kotlin.coroutines.CoroutineVerticle import io.vertx.kotlin.coroutines.coAwait -import io.vertx.micrometer.backends.BackendRegistries import io.vertx.pgclient.PgConnection import org.apache.logging.log4j.kotlin.Logging -class ServerVerticle() : CoroutineVerticle() { +class ServerVerticle : CoroutineVerticle() { override suspend fun start() { val conn = PgConnection.connect(vertx, Properties.PG_CONNECT).coAwait() @@ -31,15 +26,6 @@ class ServerVerticle() : CoroutineVerticle() { val defaultHandler = DefaultHandler() val messageHandler = MessageHandler() - val metricsHandler = if (Properties.METRICS_ENABLED) { - val registry = BackendRegistries.getDefaultNow() as PrometheusMeterRegistry - Handler { - it.response() - .putHeader(CONTENT_TYPE, "text/plain; version=0.0.4; charset=utf-8") - .end(registry.scrape()) - } - } else null - val server = vertx .createHttpServer(Properties.HTTP) .requestHandler { @@ -52,7 +38,6 @@ class ServerVerticle() : CoroutineVerticle() { 8 -> when (path) { QUERIES_PATH -> 5 UPDATES_PATH -> 6 - METRICS_PATH -> 7 else -> 0 } else -> 0 @@ -64,7 +49,6 @@ class ServerVerticle() : CoroutineVerticle() { 4 -> worldHandler.readRandomWorld(it) 5 -> worldHandler.readRandomWorlds(it) 6 -> worldHandler.updateRandomWorlds(it) - 7 -> metricsHandler?.handle(it) ?: it.response().setStatusCode(404).end() else -> it.response().setStatusCode(404).end() } } @@ -79,8 +63,7 @@ class ServerVerticle() : CoroutineVerticle() { logger.info("HTTP server started on port ${server.actualPort()}") } - companion object : Logging { - private const val METRICS_PATH = "/metrics" + private companion object : Logging { private const val PLAINTEXT_PATH = "/plaintext" private const val JSON_PATH = "/json" private const val FORTUNES_PATH = "/fortunes" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt index e12717e7228..a3ea7e4fc2b 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt @@ -12,7 +12,6 @@ import io.vertx.sqlclient.Tuple import io.vertx.sqlclient.impl.SqlClientInternal import io.vertx.sqlclient.internal.ArrayTuple import java.util.concurrent.ThreadLocalRandom -import java.util.concurrent.atomic.AtomicInteger @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") class WorldRepository private constructor( @@ -20,6 +19,7 @@ class WorldRepository private constructor( private val selectWorldQuery: PreparedQuery>, private val updateWorldQueries: Array>>, ) : AbstractRepository(conn) { + fun selectRandomWorld(): Future = selectWorldQuery .execute(Tuple.of(randomWorld())) .map { map(it.first()) } @@ -27,7 +27,7 @@ class WorldRepository private constructor( fun selectRandomWorlds(numWorlds: Int): Future> { val promise = Promise.promise>() val arr = arrayOfNulls(numWorlds) - val count = AtomicInteger(0) + var count = 0 (this.conn as SqlClientInternal).group { c -> val query = c.preparedQuery(SELECT_WORLD_SQL) repeat(numWorlds) { _ -> @@ -36,13 +36,13 @@ class WorldRepository private constructor( when { ar.succeeded() -> { val result = ar.result() - val index = count.getAndIncrement() + val index = count++ arr[index] = map(result.iterator().next()) if (index == numWorlds - 1) { promise.complete(arr as Array) } } - else -> promise.fail(ar.cause()) + else -> promise.tryFail(ar.cause()) } } } @@ -68,6 +68,7 @@ class WorldRepository private constructor( private const val SELECT_WORLD_SQL = "SELECT id, randomnumber FROM world WHERE id = $1" private inline fun randomWorld(): Int = 1 + ThreadLocalRandom.current().nextInt(10_000) + private inline fun map(row: Row): World = World( row.getInteger(0), row.getInteger(1), diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt index d34e72b5598..cfaa2cc0b31 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt @@ -19,6 +19,7 @@ abstract class AbstractHandler { // Headers val SERVER: CharSequence = HttpHeaders.createOptimized(Properties.SERVER_NAME) + val CONTENT_TYPE_TEXT_HTML: CharSequence = HttpHeaders.createOptimized("text/html; charset=UTF-8") inline fun MultiMap.common(): MultiMap = this .add(HttpHeaderNames.SERVER, SERVER) @@ -42,7 +43,7 @@ abstract class AbstractHandler { .apply { headers() .common() - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_HTML) + .add(HttpHeaderNames.CONTENT_TYPE, CONTENT_TYPE_TEXT_HTML) } inline fun HttpServerRequest.error(): Future = plaintext() diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt index 7f981320192..0b527148a7a 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt @@ -6,6 +6,7 @@ import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpServerRequest class DefaultHandler : AbstractHandler() { + fun plaintext(req: HttpServerRequest): Future = req .response().apply { headers().setAll(PeriodicResolver.plaintext) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt index 029026dab4c..2d504af1384 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt @@ -1,12 +1,16 @@ package com.example.starter.handlers +import FortunesTemplate import com.example.starter.db.FortuneRepository +import com.example.starter.helpers.BufferRockerOutput import com.example.starter.models.Fortune +import com.fizzed.rocker.ContentType import io.vertx.core.http.HttpServerRequest -import java.lang.Exception import org.apache.logging.log4j.kotlin.Logging class FortuneHandler(private val repository: FortuneRepository) : AbstractHandler() { + private val factory = BufferRockerOutput.factory(ContentType.RAW) + fun templateFortunes(req: HttpServerRequest) { repository .selectFortunes() @@ -14,11 +18,13 @@ class FortuneHandler(private val repository: FortuneRepository) : AbstractHandle when { ar.succeeded() -> { try { - val updatedFortunes = ar.result().plus(Fortune(0, "Additional fortune added at request time.")) - updatedFortunes.sort() - - val html = renderFortunes(updatedFortunes) - req.html().end(html) + val updatedFortunes = ar.result() + .plus(Fortune(0, "Additional fortune added at request time.")) + .apply { sort() } + val buffer = FortunesTemplate.template(updatedFortunes) + .render(factory) + .buffer() + req.html().end(buffer) } catch (ex: Exception) { logger.error(SOMETHING_WENT_WRONG, ex) req.error() @@ -32,9 +38,5 @@ class FortuneHandler(private val repository: FortuneRepository) : AbstractHandle } } - private companion object : Logging { - private fun renderFortunes(fortunes: Array): String { - throw NotImplementedError("Not implemented") - } - } + private companion object : Logging } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt index 0a91afea21e..7dcf99d135f 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt @@ -15,6 +15,5 @@ class MessageHandler : AbstractHandler() { companion object { const val MESSAGE: String = "Hello, World!" - val DEFAULT_MESSAGE = Message(MESSAGE) } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferRockerOutput.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferRockerOutput.kt new file mode 100644 index 00000000000..00937c04395 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferRockerOutput.kt @@ -0,0 +1,52 @@ +package com.example.starter.helpers + +import com.fizzed.rocker.ContentType +import com.fizzed.rocker.RockerOutput +import com.fizzed.rocker.RockerOutputFactory +import io.netty.buffer.ByteBuf +import io.vertx.core.buffer.Buffer +import io.vertx.core.impl.buffer.VertxByteBufAllocator +import io.vertx.core.internal.buffer.BufferInternal +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets + +class BufferRockerOutput private constructor( + private val contentType: ContentType +) : RockerOutput { + + private val byteBuf: ByteBuf = VertxByteBufAllocator.DEFAULT.directBuffer() + private val buffer: Buffer = BufferInternal.buffer(byteBuf) + + private fun reset() { + byteBuf.resetReaderIndex() + byteBuf.resetWriterIndex() + } + + override fun w(bytes: ByteArray): BufferRockerOutput { + buffer.appendBytes(bytes) + return this + } + + override fun w(s: String): BufferRockerOutput { + buffer.appendString(s) + return this + } + + override fun getContentType(): ContentType = contentType + + override fun getCharset(): Charset = StandardCharsets.UTF_8 + + override fun getByteLength(): Int = buffer.length() + + fun buffer(): Buffer = buffer + + companion object { + fun factory(contentType: ContentType): RockerOutputFactory { + val output = BufferRockerOutput(contentType) + return RockerOutputFactory { _, _ -> + output.reset() + output + } + } + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt index 4e08f883e23..d5e3962a1d7 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt @@ -1,8 +1,5 @@ package com.example.starter.helpers -import com.example.starter.handlers.DefaultHandler -import com.example.starter.handlers.MessageHandler -import com.example.starter.utils.serialize import io.vertx.core.MultiMap import io.vertx.core.Vertx import io.vertx.core.http.HttpHeaders @@ -14,8 +11,6 @@ private val FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset private val SERVER: CharSequence = HttpHeaders.createOptimized(Properties.SERVER_NAME) private val CONTENT_TYPE_TEXT_PLAIN: CharSequence = HttpHeaders.createOptimized("text/plain") private val CONTENT_TYPE_APPLICATION_JSON: CharSequence = HttpHeaders.createOptimized("application/json") -private val PLAINTEXT_CONTENT_LENGTH: CharSequence= HttpHeaders.createOptimized(DefaultHandler.MESSAGE.length.toString()) -private val JSON_CONTENT_LENGTH: CharSequence = HttpHeaders.createOptimized(MessageHandler.DEFAULT_MESSAGE.serialize().length().toString()) @Suppress("NOTHING_TO_INLINE") object PeriodicResolver { @@ -48,7 +43,6 @@ object PeriodicResolver { .add(HttpHeaders.SERVER, SERVER) .add(HttpHeaders.DATE, current) .add(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN) - .add(HttpHeaders.CONTENT_LENGTH, PLAINTEXT_CONTENT_LENGTH) .copy(false) private fun nextJson(): MultiMap = HttpHeaders @@ -56,6 +50,5 @@ object PeriodicResolver { .add(HttpHeaders.SERVER, SERVER) .add(HttpHeaders.DATE, current) .add(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON) - .add(HttpHeaders.CONTENT_LENGTH, JSON_CONTENT_LENGTH) .copy(false) } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt index ca72dd8a61c..6f0d07767b1 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt @@ -26,67 +26,12 @@ object Properties { */ val EVENT_LOOP_POOL_SIZE: Int = SystemPropertyUtil.getInt("tfb.eventLoopPoolSize", CpuCoreSensor.availableProcessors()) - /** - * Whether metrics are enabled. - * Default: Reverse of `vertx.disableMetrics` (defaults to false) - */ - val METRICS_ENABLED: Boolean = SystemPropertyUtil.getBoolean("vertx.disableMetrics", false).not() - /** * Port the HTTP server listens on. * Default: 8080 (tfb.http.port) */ val HTTP_PORT: Int = SystemPropertyUtil.getInt("tfb.http.port", 8080) - /** - * Size of TCP send buffer for HTTP connections, in bytes. - * Default: 32768 (tfb.http.sendBufferSize) - */ - val HTTP_SEND_BUFFER_SIZE: Int = SystemPropertyUtil.getInt("tfb.http.sendBufferSize", 16 * 1024) - - /** - * Size of TCP receive buffer for HTTP connections, in bytes. - * Default: 32768 (tfb.http.receiveBufferSize) - */ - val HTTP_RECEIVE_BUFFER_SIZE: Int = SystemPropertyUtil.getInt("tfb.http.receiveBufferSize", 16 * 1024) - - /** - * Enables TCP Fast Open on the HTTP server. - * Default: true (tfb.http.tcpFastOpen) - */ - val HTTP_TCP_FASTOPEN: Boolean = SystemPropertyUtil.getBoolean("tfb.http.tcpFastOpen", true) - - /** - * Enables TCP_NODELAY (disables Nagle) on HTTP connections. - * Default: true (tfb.http.tcpNoDelay) - */ - val HTTP_TCP_NODELAY: Boolean = SystemPropertyUtil.getBoolean("tfb.http.tcpNoDelay", true) - - /** - * Idle timeout for HTTP connections in seconds. - * 0 disables idle timeout. - * Default: 0 (tfb.http.idleTimeout) - */ - val HTTP_IDLE_TIMEOUT: Int = SystemPropertyUtil.getInt("tfb.http.idleTimeout", 0) - - /** - * Enables SO_REUSEADDR on the HTTP server socket. - * Default: true (tfb.http.reuseAddress) - */ - val HTTP_REUSE_ADDRESS: Boolean = SystemPropertyUtil.getBoolean("tfb.http.reuseAddress", true) - - /** - * Enables SO_REUSEPORT on the HTTP server socket. - * Default: true (tfb.http.reusePort) - */ - val HTTP_REUSE_PORT: Boolean = SystemPropertyUtil.getBoolean("tfb.http.reusePort", true) - - /** - * Size of the TCP accept backlog for the HTTP server. - * Default: 8192 (tfb.http.acceptBacklog) - */ - val HTTP_ACCEPT_BACKLOG: Int = SystemPropertyUtil.getInt("tfb.http.acceptBacklog", 8192) - /** * PostgreSQL username used for connections. * Default: benchmarkdbuser (tfb.pg.user) @@ -140,14 +85,6 @@ object Properties { val HTTP by lazy { httpServerOptionsOf( port = HTTP_PORT, - sendBufferSize = HTTP_SEND_BUFFER_SIZE, - receiveBufferSize = HTTP_RECEIVE_BUFFER_SIZE, - tcpFastOpen = HTTP_TCP_FASTOPEN, - tcpNoDelay = HTTP_TCP_NODELAY, - idleTimeout = HTTP_IDLE_TIMEOUT, - reuseAddress = HTTP_REUSE_ADDRESS, - reusePort = HTTP_REUSE_PORT, - acceptBacklog = HTTP_ACCEPT_BACKLOG, compressionSupported = false, tracingPolicy = TracingPolicy.IGNORE, http2ClearTextEnabled = false, @@ -165,7 +102,7 @@ object Properties { cachePreparedStatements = PG_CACHE_PREPARED_STATEMENTS, preparedStatementCacheMaxSize = PG_PREPARED_STATEMENT_CACHE_MAX_SIZE, tracingPolicy = TracingPolicy.IGNORE, - pipeliningLimit = PG_PIPELINING_LIMIT + pipeliningLimit = PG_PIPELINING_LIMIT, ) } } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/rocker/FortunesTemplate.rocker.html b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/rocker/FortunesTemplate.rocker.html new file mode 100644 index 00000000000..c46b97a6d0a --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/rocker/FortunesTemplate.rocker.html @@ -0,0 +1,7 @@ +@import com.example.starter.models.Fortune +@args(Fortune[] fortunes) +Fortunes +@for (int i = 0; i < fortunes.length; i++) { + +} +
idmessage
@fortunes[i].getId()@fortunes[i].getMessage()
\ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile index e75d7fbdb8a..8b33abccfe1 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile @@ -26,18 +26,22 @@ EXPOSE 8080 CMD java \ -server \ --enable-native-access=ALL-UNNAMED \ - --add-opens=java.base/java.lang=ALL-UNNAMED \ --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.nio=ALL-UNNAMED \ + --add-opens=java.base/sun.nio.ch=ALL-UNNAMED \ + --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ -Xms2G \ -Xmx2G \ + -XX:MaxDirectMemorySize=6G \ -XX:+AlwaysPreTouch \ -XX:+UseParallelGC \ + -XX:+DisableExplicitGC \ -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ - -XX:MaxInlineLevel=20 \ -XX:+UseNUMA \ - -XX:-UseCodeCacheFlushing \ - -XX:AutoBoxCacheMax=10001 \ + -XX:AutoBoxCacheMax=20000 \ + -XX:+UnlockExperimentalVMOptions \ -XX:+UseCompactObjectHeaders \ -Djava.net.preferIPv4Stack=true \ -Dvertx.disableMetrics=true \ @@ -50,7 +54,8 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.leakDetection.level=disabled \ - -Dio.netty.iouring.ringSize=4096 \ - -Dio.netty.iouring.ringSize=16384 \ + -Dio.netty.tryReflectionSetAccessible=true \ + -Dio.netty.iouring.ringSize=8192 \ + -Dio.netty.iouring.cqSize=16384 \ -Dtfb.type=postgres \ -jar /app/vertx-web-kotlin-dsljson.jar diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile index d1548a76ae9..e5d3e9f9943 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile @@ -26,18 +26,22 @@ EXPOSE 8080 CMD java \ -server \ --enable-native-access=ALL-UNNAMED \ - --add-opens=java.base/java.lang=ALL-UNNAMED \ --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.nio=ALL-UNNAMED \ + --add-opens=java.base/sun.nio.ch=ALL-UNNAMED \ + --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ -Xms2G \ -Xmx2G \ + -XX:MaxDirectMemorySize=6G \ -XX:+AlwaysPreTouch \ -XX:+UseParallelGC \ + -XX:+DisableExplicitGC \ -XX:InitialCodeCacheSize=512m \ -XX:ReservedCodeCacheSize=512m \ - -XX:MaxInlineLevel=20 \ -XX:+UseNUMA \ - -XX:-UseCodeCacheFlushing \ - -XX:AutoBoxCacheMax=10001 \ + -XX:AutoBoxCacheMax=20000 \ + -XX:+UnlockExperimentalVMOptions \ -XX:+UseCompactObjectHeaders \ -Djava.net.preferIPv4Stack=true \ -Dvertx.disableMetrics=true \ @@ -50,6 +54,8 @@ CMD java \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.leakDetection.level=disabled \ + -Dio.netty.tryReflectionSetAccessible=true \ -Dio.netty.iouring.ringSize=16384 \ + -Dio.netty.iouring.cqSize=32768 \ -Dtfb.type=basic \ -jar /app/vertx-web-kotlin-dsljson.jar diff --git a/frameworks/Kotlin/vertx-web-kotlinx/.gitattributes b/frameworks/Kotlin/vertx-web-kotlinx/.gitattributes index 097f9f98d9e..f91f64602e6 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/.gitattributes +++ b/frameworks/Kotlin/vertx-web-kotlinx/.gitattributes @@ -7,3 +7,6 @@ # These are Windows script files and should use crlf *.bat text eol=crlf +# Binary files should be left untouched +*.jar binary + diff --git a/frameworks/Kotlin/vertx-web-kotlinx/.gitignore b/frameworks/Kotlin/vertx-web-kotlinx/.gitignore new file mode 100644 index 00000000000..eb713db1967 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/.gitignore @@ -0,0 +1 @@ +.m2 diff --git a/frameworks/Kotlin/vertx-web-kotlinx/README.md b/frameworks/Kotlin/vertx-web-kotlinx/README.md index f3134cb1b35..d146cc07216 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/README.md +++ b/frameworks/Kotlin/vertx-web-kotlinx/README.md @@ -2,19 +2,19 @@ Vert.x-Web in Kotlin with request handling implemented as much with official kotlinx libraries as possible. -Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `await`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 25. +Code is written from scratch to be as concise as possible with common code extracted into common (possibly inline) functions. SQL client implementation details and JVM Options are adapted referring to [the vertx-web portion](../../Java/vertx-web) and [the vertx portion](../../Java/vertx). All requests are handled in coroutines and suspend `coAwait`s are used instead of future compositions. Compared to [the vertx-web-kotlin-coroutines portion](../vertx-web-kotlin-coroutines), besides adopting the Kotlinx libraries, this project simplifies the code by using more built-in Coroutine functions and avoids mutability as much as possible. JSON serialization is implemented with kotlinx.serialization and Fortunes with kotlinx.html. The benchmark is run on the latest LTS version of JVM, 25. ## Test Type Implementation Source Code -* [JSON](src/main/kotlin/MainVerticle.kt) +* [JSON](without-db/default/src/main/kotlin/MainVerticle.kt) implemented with kotlinx.serialization -* [PLAINTEXT](src/main/kotlin/MainVerticle.kt) -* [DB](src/main/kotlin/MainVerticle.kt) -* [QUERY](src/main/kotlin/MainVerticle.kt) -* [UPDATE](src/main/kotlin/MainVerticle.kt) -* [FORTUNES](src/main/kotlin/MainVerticle.kt) +* [PLAINTEXT](without-db/default/src/main/kotlin/MainVerticle.kt) +* [DB](with-db/default/src/main/kotlin/MainVerticle.kt) +* [QUERY](with-db/default/src/main/kotlin/MainVerticle.kt) +* [UPDATE](with-db/default/src/main/kotlin/MainVerticle.kt) +* [FORTUNES](with-db/default/src/main/kotlin/MainVerticle.kt) implemented with kotlinx.html @@ -28,6 +28,7 @@ The tests were run with: * [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) * [kotlinx-io](https://github.com/Kotlin/kotlinx-io) * [kotlinx.html](https://github.com/Kotlin/kotlinx.html) +* [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) ## Test URLs @@ -45,11 +46,11 @@ http://localhost:8080/db ### QUERY -http://localhost:8080/query?queries= +http://localhost:8080/queries?queries= ### UPDATE -http://localhost:8080/update?queries= +http://localhost:8080/updates?queries= ### FORTUNES diff --git a/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json index 826470e61f9..79f3c938cff 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlinx/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "vertx-web-kotlinx", + "maintainers": ["ShreckYe"], "tests": [ { "default": { @@ -41,7 +42,111 @@ "display_name": "vertx-web-kotlinx-postgresql", "notes": "", "versus": "vertx-web-postgres" + }, + "r2dbc-postgresql": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlinx-r2dbc-postgresql", + "notes": "", + "versus": "vertx-web-kotlinx-postgresql" + }, + "r2dbc-postgresql-separate-pool-size-1": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-1", + "notes": "Original configuration: pool size 1 per verticle, original connection factory", + "versus": "vertx-web-kotlinx-r2dbc-postgresql" + }, + "r2dbc-postgresql-separate-pool-size-8": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-8", + "notes": "Pool size 8 per verticle (~512 total on 56-core), original connection factory", + "versus": "vertx-web-kotlinx-r2dbc-postgresql" + }, + "exposed-r2dbc-postgresql": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Full", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlinx-exposed-r2dbc-postgresql", + "versus": "vertx-web-kotlinx-r2dbc-postgresql" + }, + "exposed-vertx-sql-client-postgresql": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Full", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlinx-exposed-vertx-sql-client-postgresql", + "notes": "", + "versus": "vertx-web-kotlinx-postgresql" } } ] -} +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts index 57ecdf9e59a..1eaea6e9b87 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts @@ -1,39 +1,8 @@ -tasks.wrapper { - distributionType = Wrapper.DistributionType.ALL -} - plugins { - val kotlinVersion = "2.3.0-RC2" - kotlin("jvm") version kotlinVersion - kotlin("plugin.serialization") version kotlinVersion - application + //id("nl.littlerobots.version-catalog-update") version "1.0.1" + id("com.github.ben-manes.versions") version "0.53.0" } -repositories { - mavenCentral() -} - -val vertxVersion = "5.0.5" -val kotlinxSerializationVersion = "1.9.0" -dependencies { - implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion")) - implementation("io.vertx:vertx-web") - implementation("io.vertx:vertx-pg-client") - //implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") - implementation("io.netty", "netty-transport-native-io_uring", classifier = "linux-x86_64") - implementation("io.vertx:vertx-lang-kotlin") - implementation("io.vertx:vertx-lang-kotlin-coroutines") - - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-io:$kotlinxSerializationVersion") - implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.8.2") - - implementation("org.jetbrains.kotlinx:kotlinx-html:0.12.0") - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1") +tasks.wrapper { + distributionType = Wrapper.DistributionType.ALL } - -kotlin.jvmToolchain(25) - -application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/build.gradle.kts new file mode 100644 index 00000000000..ab41a608f2c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + `kotlin-dsl` + // to resolve the `Kotlin does not yet support 25 JDK target, falling back to Kotlin JVM_24 JVM target` warning + kotlin("jvm") version libs.versions.kotlin +} + +repositories { + gradlePluginPortal() +} + +dependencies { + implementation(libs.kotlin.gradle.plugin) +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/settings.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/settings.gradle.kts new file mode 100644 index 00000000000..a87e827e580 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/settings.gradle.kts @@ -0,0 +1,8 @@ +dependencyResolutionManagement { + // Reuse version catalog from the main build. + versionCatalogs { + create("libs", { from(files("../gradle/libs.versions.toml")) }) + } +} + +rootProject.name = "buildSrc" diff --git a/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-application-conventions.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-application-conventions.gradle.kts new file mode 100644 index 00000000000..09bc3da136c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-application-conventions.gradle.kts @@ -0,0 +1,4 @@ +plugins { + id("buildlogic.kotlin-common-conventions") + application +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-common-conventions.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-common-conventions.gradle.kts new file mode 100644 index 00000000000..f18d807f638 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-common-conventions.gradle.kts @@ -0,0 +1,9 @@ +plugins { + kotlin("jvm") +} + +repositories { + mavenCentral() +} + +kotlin.jvmToolchain(25) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-library-conventions.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-library-conventions.gradle.kts new file mode 100644 index 00000000000..23f5a3a5965 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/buildSrc/src/main/kotlin/buildlogic.kotlin-library-conventions.gradle.kts @@ -0,0 +1,4 @@ +plugins { + id("buildlogic.kotlin-common-conventions") + `java-library` +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/common/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/common/build.gradle.kts new file mode 100644 index 00000000000..0980f54095e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/common/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + id("buildlogic.kotlin-library-conventions") + alias(libs.plugins.kotlin.plugin.serialization) +} + +dependencies { + api(platform(libs.vertx.stack.depchain)) + api(libs.vertx.web) + //runtimeOnly("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + runtimeOnly(libs.netty.transport.native.iouring) { artifact { classifier = "linux-x86_64" } } + api(libs.vertx.lang.kotlin) + api(libs.vertx.lang.kotlin.coroutines) + + implementation(libs.kotlinx.coroutines.core) + + api(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.serialization.json.io) + implementation(libs.kotlinx.io.core) + + implementation(libs.kotlinx.datetime) +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/CommonMain.kt b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/CommonMain.kt new file mode 100644 index 00000000000..2c002d21946 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/CommonMain.kt @@ -0,0 +1,35 @@ +import io.vertx.core.Verticle +import io.vertx.core.Vertx +import io.vertx.core.impl.cpu.CpuCoreSensor +import io.vertx.kotlin.core.deploymentOptionsOf +import io.vertx.kotlin.core.vertxOptionsOf +import io.vertx.kotlin.coroutines.coAwait +import java.util.function.Supplier +import java.util.logging.Logger + +val numProcessors = CpuCoreSensor.availableProcessors() + +val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark") +suspend fun commonRunVertxServer( + benchmarkName: String, + createSharedResources: (Vertx) -> SharedResources, + createVerticle: (SharedResources) -> Verticle +) { + val serverName = "$benchmarkName benchmark server" + logger.info("$serverName starting...") + val vertx = Vertx.vertx( + vertxOptionsOf( + eventLoopPoolSize = numProcessors, preferNativeTransport = true, disableTCCL = true + ) + ) + vertx.exceptionHandler { + logger.info("Vertx exception caught: $it") + it.printStackTrace() + } + val sharedResources = createSharedResources(vertx) + vertx.deployVerticle( + Supplier { createVerticle(sharedResources) }, + deploymentOptionsOf(instances = numProcessors) + ).coAwait() + logger.info("$serverName started.") +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/CommonVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/CommonVerticle.kt new file mode 100644 index 00000000000..fbf0d981f7b --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/CommonVerticle.kt @@ -0,0 +1,164 @@ +import io.netty.channel.unix.Errors +import io.netty.channel.unix.Errors.NativeIoException +import io.vertx.core.MultiMap +import io.vertx.core.buffer.Buffer +import io.vertx.core.http.HttpHeaders +import io.vertx.core.http.HttpServer +import io.vertx.core.http.HttpServerResponse +import io.vertx.ext.web.Route +import io.vertx.ext.web.Router +import io.vertx.ext.web.RoutingContext +import io.vertx.kotlin.core.http.httpServerOptionsOf +import io.vertx.kotlin.coroutines.CoroutineRouterSupport +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.coAwait +import kotlinx.coroutines.Dispatchers +import kotlinx.datetime.UtcOffset +import kotlinx.datetime.format.* +import kotlinx.datetime.format.DateTimeComponents.Companion.Format +import kotlinx.io.buffered +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.json.io.encodeToSink +import java.net.SocketException +import kotlin.random.Random +import kotlin.time.Clock + +abstract class CommonVerticle : CoroutineVerticle(), CoroutineRouterSupport { + object HttpHeaderValues { + val vertxWeb = HttpHeaders.createOptimized("Vert.x-Web") + val applicationJson = HttpHeaders.createOptimized("application/json") + val textHtmlCharsetUtf8 = HttpHeaders.createOptimized("text/html; charset=utf-8") + val textPlain = HttpHeaders.createOptimized("text/plain") + } + + lateinit var httpServer: HttpServer + lateinit var date: String + + object DateTimeComponentsFormats { + // adapted from `DateTimeComponents.Formats.RFC_1123` with the second field made mandatory + val RFC_1123_WITH_MANDATORY_SECOND = Format { + alternativeParsing({ + // the day of week may be missing + }) { + dayOfWeek(DayOfWeekNames.ENGLISH_ABBREVIATED) + chars(", ") + } + day(Padding.NONE) + char(' ') + monthName(MonthNames.ENGLISH_ABBREVIATED) + char(' ') + year() + char(' ') + hour() + char(':') + minute() + char(':') + second() + chars(" ") + alternativeParsing({ + chars("UT") + }, { + chars("Z") + }) { + optional("GMT") { + offset(UtcOffset.Formats.FOUR_DIGITS) + } + } + } + } + + fun setCurrentDate() { + date = DateTimeComponentsFormats.RFC_1123_WITH_MANDATORY_SECOND.format { + // We don't need a more complicated system `TimeZone` here (whose offset depends dynamically on the actual time due to DST) since UTC works. + setDateTimeOffset(Clock.System.now(), UtcOffset.ZERO) + } + } + + override suspend fun start() { + setCurrentDate() + vertx.setPeriodic(1000) { setCurrentDate() } + httpServer = vertx.createHttpServer( + httpServerOptionsOf( + port = 8080, + http2ClearTextEnabled = false, + strictThreadMode = httpServerStrictThreadMode + ) + ) + .requestHandler(Router.router(vertx).apply { routes() }) + .exceptionHandler { + // wrk resets the connections when benchmarking is finished. + if ((/* for native transport */it is NativeIoException && it.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE) || + (/* for Java NIO */ it is SocketException && it.message == "Connection reset") + ) + return@exceptionHandler + + logger.info("Exception in HttpServer: $it") + it.printStackTrace() + } + .listen().coAwait() + } + + // set to `false` to resolve `java.lang.IllegalStateException: Only the context thread can write a message + open val httpServerStrictThreadMode get() = true + + abstract fun Router.routes() + + @Suppress("NOTHING_TO_INLINE") + inline fun MultiMap.addCommonHeaders() { + add(HttpHeaders.SERVER, HttpHeaderValues.vertxWeb) + add(HttpHeaders.DATE, date) + } + + @Suppress("NOTHING_TO_INLINE") + inline fun HttpServerResponse.addJsonResponseHeaders() { + headers().run { + addCommonHeaders() + add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.applicationJson) + } + } + + + fun Route.coHandlerUnconfined(requestHandler: suspend (RoutingContext) -> Unit): Route = + /* Some conclusions from the Plaintext test results with trailing `await()`s: + 1. `launch { /*...*/ }` < `launch(start = CoroutineStart.UNDISPATCHED) { /*...*/ }` < `launch(Dispatchers.Unconfined) { /*...*/ }`. + 1. `launch { /*...*/ }` without `context` or `start` lead to `io.netty.channel.StacklessClosedChannelException` and `io.netty.channel.unix.Errors$NativeIoException: sendAddress(..) failed: Connection reset by peer`. */ + coHandler(Dispatchers.Unconfined, requestHandler) + + // an alternative way + // set to `EmptyCoroutineContext` to resolve `java.lang.IllegalStateException: Only the context thread can write a message + //open val coHandlerCoroutineContext: CoroutineContext get() = Dispatchers.Unconfined + + inline fun Route.jsonResponseCoHandler( + serializer: SerializationStrategy, + crossinline requestHandler: suspend (RoutingContext) -> @Serializable T + ) = + coHandlerUnconfined { + it.response().run { + addJsonResponseHeaders() + + /* + // Approach 1 + end(json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/ + */ + + /* + // Approach 2 + // java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding. + toRawSink().buffered().use { bufferedSink -> + @OptIn(ExperimentalSerializationApi::class) + json.encodeToSink(serializer, requestHandler(it), bufferedSink) + } + */ + + // Approach 3 + end(Buffer.buffer().apply { + toRawSink().buffered().use { bufferedSink -> + @OptIn(ExperimentalSerializationApi::class) + json.encodeToSink(serializer, requestHandler(it), bufferedSink) + } + }) + } + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/KotlinxIo.kt similarity index 100% rename from frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt rename to frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/KotlinxIo.kt diff --git a/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/Models.kt b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/Models.kt new file mode 100644 index 00000000000..85b5aad2bba --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/Models.kt @@ -0,0 +1,13 @@ +import kotlinx.serialization.Serializable +import kotlin.random.Random + +@Serializable +class Message(val message: String) + +@Serializable +data class World(val id: Int, val randomNumber: Int) + +fun Random.nextIntBetween1And10000() = + nextInt(1, 10001) + +class Fortune(val id: Int, val message: String) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/Serialization.kt b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/Serialization.kt new file mode 100644 index 00000000000..65e8b3f6766 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/Serialization.kt @@ -0,0 +1,17 @@ +import kotlinx.serialization.json.Json +import kotlinx.serialization.serializer + +// copied from the `ktor` portion +// Optimized JSON instance with better performance settings +val json = Json { + prettyPrint = false + isLenient = true + ignoreUnknownKeys = true + coerceInputValues = true +} + +object Serializers { + val message = serializer() + val world = serializer() + val worlds = serializer>() +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt b/frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/VertxCoroutine.kt similarity index 100% rename from frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt rename to frameworks/Kotlin/vertx-web-kotlinx/common/src/main/kotlin/VertxCoroutine.kt diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle.properties b/frameworks/Kotlin/vertx-web-kotlinx/gradle.properties index f97ebb7d334..c23c8dcaf1c 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradle.properties +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradle.properties @@ -1 +1,2 @@ -org.gradle.parallel=true +#org.gradle.parallel=true # disabled for the `dependencyUpdates` task +org.gradle.configuration-cache=true diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/libs.versions.toml b/frameworks/Kotlin/vertx-web-kotlinx/gradle/libs.versions.toml new file mode 100644 index 00000000000..ba91ca06e1b --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradle/libs.versions.toml @@ -0,0 +1,63 @@ +[versions] +kotlin = "2.3.0" +vertx = "5.0.7" +kotlinx-coroutines = "1.10.2" +kotlinx-serialization = "1.10.0" +kotlinx-io = "0.8.2" +kotlinx-html = "0.12.0" +kotlinx-datetime = "0.7.1" +r2dbc-spi = "1.0.0.RELEASE" +r2dbc-postgresql = "1.1.1.RELEASE" +r2dbc-pool = "1.0.2.RELEASE" +exposed = "1.0.0" +exposedVertxSqlClient = "0.8.0" + +[libraries] +# Kotlin Gradle plugin as a library for buildSrc +kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } + +# Vert.x BOM (depchain) and modules + +vertx-stack-depchain = { module = "io.vertx:vertx-stack-depchain", version.ref = "vertx" } +vertx-web = { module = "io.vertx:vertx-web" } +vertx-pgClient = { module = "io.vertx:vertx-pg-client" } +vertx-lang-kotlin = { module = "io.vertx:vertx-lang-kotlin" } +vertx-lang-kotlin-coroutines = { module = "io.vertx:vertx-lang-kotlin-coroutines" } + +# Netty native transport (version managed transitively by Vert.x) +netty-transport-native-iouring = { module = "io.netty:netty-transport-native-io_uring" } + + +# KotlinX libraries + +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-reactive = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactive", version.ref = "kotlinx-coroutines" } + +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } +kotlinx-serialization-json-io = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-io", version.ref = "kotlinx-serialization" } + +kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" } + +kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } + +kotlinx-html = { module = "org.jetbrains.kotlinx:kotlinx-html", version.ref = "kotlinx-html" } + + +# R2DBC SPI and PostgreSQL driver +r2dbc-spi = { module = "io.r2dbc:r2dbc-spi", version.ref = "r2dbc-spi" } +r2dbc-postgresql = { module = "org.postgresql:r2dbc-postgresql", version.ref = "r2dbc-postgresql" } +r2dbc-pool = { module = "io.r2dbc:r2dbc-pool", version.ref = "r2dbc-pool" } + + +# Exposed +exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } +exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } +exposed-r2dbc = { module = "org.jetbrains.exposed:exposed-r2dbc", version.ref = "exposed" } + + +# Exposed Vert.x SQL Client +exposedVertxSqlClient-core = { module = "com.huanshankeji:exposed-vertx-sql-client-core", version.ref = "exposedVertxSqlClient" } +exposedVertxSqlClient-postgresql = { module = "com.huanshankeji:exposed-vertx-sql-client-postgresql", version.ref = "exposedVertxSqlClient" } + +[plugins] +kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar index f8e1ee3125f..61285a659d1 100644 Binary files a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties index 4eac4a84cc3..5f38436fc6e 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/vertx-web-kotlinx/settings.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/settings.gradle.kts index 17b1f42607d..7440535eb2c 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/settings.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlinx/settings.gradle.kts @@ -1 +1,23 @@ rootProject.name = "vertx-web-kotlinx-benchmark" + +include( + "common", + + "without-db:default", + + "with-db:common", + "with-db:default", + "with-db:r2dbc-common", + "with-db:r2dbc", + //"with-db:r2dbc:jasync", // TODO + "with-db:exposed-common", + /* + "with-db:exposed-common:jdbc", + "with-db:exposed-common:r2dbc", + */ + "with-db:exposed-r2dbc", + "with-db:exposed-vertx-sql-client" +) + +// renamed explicitly to work around jar name conflicts +project(":with-db:common").name = "with-db-common" diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Database.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Database.kt deleted file mode 100644 index aed4e5e29a0..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Database.kt +++ /dev/null @@ -1,12 +0,0 @@ -import io.vertx.sqlclient.Row - -const val SELECT_WORLD_SQL = "SELECT id, randomnumber from WORLD where id = $1" -const val UPDATE_WORLD_SQL = "UPDATE world SET randomnumber = $1 WHERE id = $2" -const val SELECT_FORTUNE_SQL = "SELECT id, message from FORTUNE" - - -fun Row.toWorld() = - World(getInteger(0), getInteger(1)) - -fun Row.toFortune() = - Fortune(getInteger(0), getString(1)) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt deleted file mode 100644 index 52864f79f16..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt +++ /dev/null @@ -1,32 +0,0 @@ -import io.vertx.core.Vertx -import io.vertx.core.impl.cpu.CpuCoreSensor -import io.vertx.kotlin.core.deploymentOptionsOf -import io.vertx.kotlin.core.vertxOptionsOf -import io.vertx.kotlin.coroutines.coAwait -import java.util.function.Supplier -import java.util.logging.Logger - -const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark server" -val numProcessors = CpuCoreSensor.availableProcessors() - -val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark") -suspend fun main(args: Array) { - val hasDb = args.getOrNull(0)?.toBooleanStrictOrNull() - ?: throw IllegalArgumentException("Specify the first `hasDb` Boolean argument") - - logger.info("$SERVER_NAME starting...") - val vertx = Vertx.vertx( - vertxOptionsOf( - eventLoopPoolSize = numProcessors, preferNativeTransport = true, disableTCCL = true - ) - ) - vertx.exceptionHandler { - logger.info("Vertx exception caught: $it") - it.printStackTrace() - } - vertx.deployVerticle( - Supplier { MainVerticle(hasDb) }, - deploymentOptionsOf(instances = numProcessors) - ).coAwait() - logger.info("$SERVER_NAME started.") -} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt deleted file mode 100644 index d12330de363..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt +++ /dev/null @@ -1,252 +0,0 @@ -import io.netty.channel.unix.Errors -import io.netty.channel.unix.Errors.NativeIoException -import io.vertx.core.MultiMap -import io.vertx.core.buffer.Buffer -import io.vertx.core.http.HttpHeaders -import io.vertx.core.http.HttpServer -import io.vertx.core.http.HttpServerRequest -import io.vertx.core.http.HttpServerResponse -import io.vertx.ext.web.Route -import io.vertx.ext.web.Router -import io.vertx.ext.web.RoutingContext -import io.vertx.kotlin.core.http.httpServerOptionsOf -import io.vertx.kotlin.coroutines.CoroutineRouterSupport -import io.vertx.kotlin.coroutines.CoroutineVerticle -import io.vertx.kotlin.coroutines.coAwait -import io.vertx.kotlin.pgclient.pgConnectOptionsOf -import io.vertx.pgclient.PgConnection -import io.vertx.sqlclient.PreparedQuery -import io.vertx.sqlclient.Row -import io.vertx.sqlclient.RowSet -import io.vertx.sqlclient.Tuple -import kotlinx.coroutines.Dispatchers -import kotlinx.datetime.UtcOffset -import kotlinx.datetime.format.DateTimeComponents -import kotlinx.datetime.format.format -import kotlinx.html.* -import kotlinx.html.stream.appendHTML -import kotlinx.io.buffered -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.io.encodeToSink -import java.net.SocketException -import kotlin.time.Clock - -class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSupport { - object HttpHeaderValues { - val vertxWeb = HttpHeaders.createOptimized("Vert.x-Web") - val applicationJson = HttpHeaders.createOptimized("application/json") - val textHtmlCharsetUtf8 = HttpHeaders.createOptimized("text/html; charset=utf-8") - val textPlain = HttpHeaders.createOptimized("text/plain") - } - - // `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s. - lateinit var pgConnection: PgConnection - lateinit var date: String - lateinit var httpServer: HttpServer - - lateinit var selectWorldQuery: PreparedQuery> - lateinit var selectFortuneQuery: PreparedQuery> - lateinit var updateWorldQuery: PreparedQuery> - - fun setCurrentDate() { - date = DateTimeComponents.Formats.RFC_1123.format { - // We don't need a more complicated system `TimeZone` here (whose offset depends dynamically on the actual time due to DST) since UTC works. - setDateTimeOffset(Clock.System.now(), UtcOffset.ZERO) - } - } - - override suspend fun start() { - if (hasDb) { - // Parameters are copied from the "vertx-web" and "vertx" portions. - pgConnection = PgConnection.connect( - vertx, - pgConnectOptionsOf( - database = "hello_world", - host = "tfb-database", - user = "benchmarkdbuser", - password = "benchmarkdbpass", - cachePreparedStatements = true, - pipeliningLimit = 256 - ) - ).coAwait() - - selectWorldQuery = pgConnection.preparedQuery(SELECT_WORLD_SQL) - selectFortuneQuery = pgConnection.preparedQuery(SELECT_FORTUNE_SQL) - updateWorldQuery = pgConnection.preparedQuery(UPDATE_WORLD_SQL) - } - - setCurrentDate() - vertx.setPeriodic(1000) { setCurrentDate() } - httpServer = vertx.createHttpServer( - httpServerOptionsOf(port = 8080, http2ClearTextEnabled = false, strictThreadMode = true) - ) - .requestHandler(Router.router(vertx).apply { routes() }) - .exceptionHandler { - // wrk resets the connections when benchmarking is finished. - if ((/* for native transport */it is NativeIoException && it.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE) || - (/* for Java NIO */ it is SocketException && it.message == "Connection reset") - ) - return@exceptionHandler - - logger.info("Exception in HttpServer: $it") - it.printStackTrace() - } - .listen().coAwait() - } - - - fun HttpServerRequest.getQueries(): Int { - val queriesParam: String? = getParam("queries") - return queriesParam?.toIntOrNull()?.coerceIn(1, 500) ?: 1 - } - - @Suppress("NOTHING_TO_INLINE") - inline fun MultiMap.addCommonHeaders() { - add(HttpHeaders.SERVER, HttpHeaderValues.vertxWeb) - add(HttpHeaders.DATE, date) - } - - @Suppress("NOTHING_TO_INLINE") - inline fun HttpServerResponse.addJsonResponseHeaders() { - headers().run { - addCommonHeaders() - add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.applicationJson) - } - } - - - fun Route.coHandlerUnconfined(requestHandler: suspend (RoutingContext) -> Unit): Route = - /* Some conclusions from the Plaintext test results with trailing `await()`s: - 1. `launch { /*...*/ }` < `launch(start = CoroutineStart.UNDISPATCHED) { /*...*/ }` < `launch(Dispatchers.Unconfined) { /*...*/ }`. - 1. `launch { /*...*/ }` without `context` or `start` lead to `io.netty.channel.StacklessClosedChannelException` and `io.netty.channel.unix.Errors$NativeIoException: sendAddress(..) failed: Connection reset by peer`. */ - coHandler(Dispatchers.Unconfined, requestHandler) - - inline fun Route.jsonResponseCoHandler( - serializer: SerializationStrategy, - crossinline requestHandler: suspend (RoutingContext) -> @Serializable T - ) = - coHandlerUnconfined { - it.response().run { - addJsonResponseHeaders() - - /* - // Approach 1 - end(Json.encodeToString(serializer, requestHandler(it)))/*.coAwait()*/ - */ - - /* - // Approach 2 - // java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding. - toRawSink().buffered().use { bufferedSink -> - @OptIn(ExperimentalSerializationApi::class) - Json.encodeToSink(serializer, requestHandler(it), bufferedSink) - } - */ - - // Approach 3 - end(Buffer.buffer().apply { - toRawSink().buffered().use { bufferedSink -> - @OptIn(ExperimentalSerializationApi::class) - Json.encodeToSink(serializer, requestHandler(it), bufferedSink) - } - }) - } - } - - - suspend fun selectRandomWorlds(queries: Int): List { - val rowSets = List(queries) { - selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())) - }.awaitAll() - return rowSets.map { it.single().toWorld() } - } - - fun Router.routes() { - get("/json").jsonResponseCoHandler(Serializers.message) { - Message("Hello, World!") - } - - get("/db").jsonResponseCoHandler(Serializers.world) { - val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).coAwait() - rowSet.single().toWorld() - } - - get("/queries").jsonResponseCoHandler(Serializers.worlds) { - val queries = it.request().getQueries() - selectRandomWorlds(queries) - } - - get("/fortunes").coHandlerUnconfined { - val fortunes = mutableListOf() - selectFortuneQuery.execute().coAwait() - .mapTo(fortunes) { it.toFortune() } - - fortunes.add(Fortune(0, "Additional fortune added at request time.")) - fortunes.sortBy { it.message } - - val htmlString = buildString { - append("") - appendHTML(false).html { - head { - title("Fortunes") - } - body { - table { - tr { - th { +"id" } - th { +"message" } - } - for (fortune in fortunes) - tr { - td { +fortune.id.toString() } - td { +fortune.message } - } - } - } - } - } - - it.response().run { - headers().run { - addCommonHeaders() - add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textHtmlCharsetUtf8) - } - end(htmlString)/*.coAwait()*/ - } - } - - // Some changes to this part in the `vertx` portion in #9142 are not ported. - get("/updates").jsonResponseCoHandler(Serializers.worlds) { - val queries = it.request().getQueries() - val worlds = selectRandomWorlds(queries) - val updatedWorlds = worlds.map { it.copy(randomNumber = randomIntBetween1And10000()) } - - // Approach 1 - // The updated worlds need to be sorted first to avoid deadlocks. - updateWorldQuery - .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).coAwait() - - /* - // Approach 2, worse performance - updatedWorlds.map { - pgPool.preparedQuery(UPDATE_WORLD_SQL).execute(Tuple.of(it.randomNumber, it.id)) - }.awaitAll() - */ - - updatedWorlds - } - - get("/plaintext").coHandlerUnconfined { - it.response().run { - headers().run { - addCommonHeaders() - add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textPlain) - } - end("Hello, World!")/*.coAwait()*/ - } - } - } -} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt deleted file mode 100644 index ae32b278863..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt +++ /dev/null @@ -1,13 +0,0 @@ -import kotlinx.serialization.Serializable -import kotlin.random.Random - -@Serializable -class Message(val message: String) - -@Serializable -data class World(val id: Int, val randomNumber: Int) - -fun randomIntBetween1And10000() = - Random.nextInt(1, 10001) - -class Fortune(val id: Int, val message: String) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt deleted file mode 100644 index c975fc07fdd..00000000000 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt +++ /dev/null @@ -1,7 +0,0 @@ -import kotlinx.serialization.serializer - -object Serializers { - val message = serializer() - val world = serializer() - val worlds = serializer>() -} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-exposed-r2dbc-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-exposed-r2dbc-postgresql.dockerfile new file mode 100644 index 00000000000..8d28c1016d5 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-exposed-r2dbc-postgresql.dockerfile @@ -0,0 +1,56 @@ +FROM gradle:9.3.1-jdk25 + +WORKDIR /vertx-web-kotlinx + + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc +COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY with-db/common/build.gradle.kts with-db/common/build.gradle.kts +COPY with-db/common/src with-db/common/src + +COPY with-db/r2dbc-common/build.gradle.kts with-db/r2dbc-common/build.gradle.kts +COPY with-db/r2dbc-common/src with-db/r2dbc-common/src + +COPY with-db/exposed-common/build.gradle.kts with-db/exposed-common/build.gradle.kts +COPY with-db/exposed-common/src with-db/exposed-common/src + +COPY with-db/exposed-r2dbc/build.gradle.kts with-db/exposed-r2dbc/build.gradle.kts +COPY with-db/exposed-r2dbc/src with-db/exposed-r2dbc/src + + +RUN gradle --no-daemon with-db:exposed-r2dbc:installDist + +EXPOSE 8080 + +CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -server \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ + " && \ + with-db/exposed-r2dbc/build/install/exposed-r2dbc/bin/exposed-r2dbc diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-exposed-vertx-sql-client-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-exposed-vertx-sql-client-postgresql.dockerfile new file mode 100644 index 00000000000..0c9e941662b --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-exposed-vertx-sql-client-postgresql.dockerfile @@ -0,0 +1,58 @@ +FROM gradle:9.3.1-jdk25 + +WORKDIR /vertx-web-kotlinx + + +# copy the Maven local dependencies into the container for snapshot dependencies +# First publish with `publishToMavenLocal` and copy the Maven local dependencies into this directory with `cp -r ~/.m2 ./`. +#COPY .m2/repository/com/huanshankeji/exposed-vertx-sql-client-core/0.8.0-SNAPSHOT /root/.m2/repository/com/huanshankeji/exposed-vertx-sql-client-core/0.8.0-SNAPSHOT +#COPY .m2/repository/com/huanshankeji/exposed-vertx-sql-client-postgresql/0.8.0-SNAPSHOT /root/.m2/repository/com/huanshankeji/exposed-vertx-sql-client-postgresql/0.8.0-SNAPSHOT + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc +COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY with-db/common/build.gradle.kts with-db/common/build.gradle.kts +COPY with-db/common/src with-db/common/src + +COPY with-db/exposed-common/build.gradle.kts with-db/exposed-common/build.gradle.kts +COPY with-db/exposed-common/src with-db/exposed-common/src + +COPY with-db/exposed-vertx-sql-client/build.gradle.kts with-db/exposed-vertx-sql-client/build.gradle.kts +COPY with-db/exposed-vertx-sql-client/src with-db/exposed-vertx-sql-client/src + + +RUN gradle --no-daemon with-db:exposed-vertx-sql-client:installDist + +EXPOSE 8080 + +CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -server \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ + " && \ + with-db/exposed-vertx-sql-client/build/install/exposed-vertx-sql-client/bin/exposed-vertx-sql-client diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile index 148962d7948..903e2164ccc 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile @@ -1,11 +1,28 @@ -FROM gradle:9.2.1-jdk25 +FROM gradle:9.3.1-jdk25 WORKDIR /vertx-web-kotlinx -COPY build.gradle.kts build.gradle.kts + + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts COPY gradle.properties gradle.properties -COPY src src -RUN gradle --no-daemon installDist + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY with-db/common/build.gradle.kts with-db/common/build.gradle.kts +COPY with-db/common/src with-db/common/src + +COPY with-db/default/build.gradle.kts with-db/default/build.gradle.kts +COPY with-db/default/src with-db/default/src + + +RUN gradle --no-daemon with-db:default:installDist EXPOSE 8080 @@ -30,4 +47,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.iouring.ringSize=16384 \ " && \ - build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true + with-db/default/build/install/default/bin/default diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-1.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-1.dockerfile new file mode 100644 index 00000000000..07d73535993 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-1.dockerfile @@ -0,0 +1,53 @@ +FROM gradle:9.3.1-jdk25 + +WORKDIR /vertx-web-kotlinx + + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc +COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY with-db/common/build.gradle.kts with-db/common/build.gradle.kts +COPY with-db/common/src with-db/common/src + +COPY with-db/r2dbc-common/build.gradle.kts with-db/r2dbc-common/build.gradle.kts +COPY with-db/r2dbc-common/src with-db/r2dbc-common/src + +COPY with-db/r2dbc/build.gradle.kts with-db/r2dbc/build.gradle.kts +COPY with-db/r2dbc/src with-db/r2dbc/src + + +RUN gradle --no-daemon with-db:r2dbc:installDist + +EXPOSE 8080 + +CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -server \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ + " && \ + with-db/r2dbc/build/install/r2dbc/bin/r2dbc false 1 false diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-8.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-8.dockerfile new file mode 100644 index 00000000000..8ae826ecd1a --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql-separate-pool-size-8.dockerfile @@ -0,0 +1,53 @@ +FROM gradle:9.3.1-jdk25 + +WORKDIR /vertx-web-kotlinx + + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc +COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY with-db/common/build.gradle.kts with-db/common/build.gradle.kts +COPY with-db/common/src with-db/common/src + +COPY with-db/r2dbc-common/build.gradle.kts with-db/r2dbc-common/build.gradle.kts +COPY with-db/r2dbc-common/src with-db/r2dbc-common/src + +COPY with-db/r2dbc/build.gradle.kts with-db/r2dbc/build.gradle.kts +COPY with-db/r2dbc/src with-db/r2dbc/src + + +RUN gradle --no-daemon with-db:r2dbc:installDist + +EXPOSE 8080 + +CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -server \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ + " && \ + with-db/r2dbc/build/install/r2dbc/bin/r2dbc false 8 false diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql.dockerfile new file mode 100644 index 00000000000..4c1c3361e38 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-r2dbc-postgresql.dockerfile @@ -0,0 +1,53 @@ +FROM gradle:9.3.1-jdk25 + +WORKDIR /vertx-web-kotlinx + + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc +COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts +COPY gradle.properties gradle.properties + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY with-db/common/build.gradle.kts with-db/common/build.gradle.kts +COPY with-db/common/src with-db/common/src + +COPY with-db/r2dbc-common/build.gradle.kts with-db/r2dbc-common/build.gradle.kts +COPY with-db/r2dbc-common/src with-db/r2dbc-common/src + +COPY with-db/r2dbc/build.gradle.kts with-db/r2dbc/build.gradle.kts +COPY with-db/r2dbc/src with-db/r2dbc/src + + +RUN gradle --no-daemon with-db:r2dbc:installDist + +EXPOSE 8080 + +CMD export JAVA_OPTS=" \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -server \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.iouring.ringSize=16384 \ + " && \ + with-db/r2dbc/build/install/r2dbc/bin/r2dbc diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile index 86382573446..34cd3dc8f70 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile @@ -1,11 +1,25 @@ -FROM gradle:9.2.1-jdk25 +FROM gradle:9.3.1-jdk25 WORKDIR /vertx-web-kotlinx -COPY build.gradle.kts build.gradle.kts + + +COPY gradle/libs.versions.toml gradle/libs.versions.toml +COPY buildSrc buildSrc COPY settings.gradle.kts settings.gradle.kts +COPY build.gradle.kts build.gradle.kts COPY gradle.properties gradle.properties -COPY src src -RUN gradle --no-daemon installDist + +# make empty directories for subprojects that do not need to be copied for Gradle +RUN mkdir -p common without-db/default with-db/common with-db/default with-db/r2dbc-common with-db/r2dbc with-db/exposed-common with-db/exposed-r2dbc with-db/exposed-vertx-sql-client + +COPY common/build.gradle.kts common/build.gradle.kts +COPY common/src common/src + +COPY without-db/default/build.gradle.kts without-db/default/build.gradle.kts +COPY without-db/default/src without-db/default/src + + +RUN gradle --no-daemon without-db:default:installDist EXPOSE 8080 @@ -30,4 +44,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkAccessible=false \ -Dio.netty.iouring.ringSize=16384 \ " && \ - build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false + without-db/default/build/install/default/bin/default diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/build.gradle.kts new file mode 100644 index 00000000000..39a86379d71 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("buildlogic.kotlin-library-conventions") + alias(libs.plugins.kotlin.plugin.serialization) +} + +dependencies { + api(project(":common")) + + implementation(libs.kotlinx.html) +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/CommonWithDbVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/CommonWithDbVerticle.kt new file mode 100644 index 00000000000..bf101127350 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/CommonWithDbVerticle.kt @@ -0,0 +1,158 @@ +import io.vertx.core.http.HttpHeaders +import io.vertx.core.http.HttpServerRequest +import io.vertx.ext.web.Router +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.html.* +import kotlinx.html.stream.appendHTML +import kotlin.random.Random + +interface CommonWithDbVerticleI : CoroutineScope { + /** + * Override this method to run [block] with a transaction. + * The methods below [selectWorld], [selectRandomWorlds], and [updateSortedWorlds] are all run in this [block], + * and should not create transactions on their own. + */ + suspend fun withOptionalTransaction(block: suspend OptionalTransaction.() -> T): T + + + suspend fun OptionalTransaction.selectWorld(id: Int): World + + val random: Random + + suspend fun OptionalTransaction.selectRandomWorld() = + selectWorld(random.nextIntBetween1And10000()) + + suspend fun OptionalTransaction.selectRandomWorlds(queries: Int): List + + suspend fun OptionalTransaction.updateSortedWorlds(sortedWorlds: List) + + suspend fun OptionalTransaction.selectFortunesInto(fortunes: MutableList) + + + interface ParallelOrPipelinedSelectWorlds : + CommonWithDbVerticleI { + override suspend fun OptionalTransaction.selectRandomWorlds(queries: Int): List = + //List(queries) { async { selectRandomWorld() } }.awaitAll() + // This should be slightly more efficient. + awaitAll(*Array(queries) { async { selectRandomWorld() } }) + } + + interface SequentialSelectWorlds : + CommonWithDbVerticleI { + override suspend fun OptionalTransaction.selectRandomWorlds(queries: Int): List = + List(queries) { selectRandomWorld() } + } + + //interface WithoutTransaction : CommonWithDbVerticleI { // This doesn't work in Kotlin. + interface WithoutTransaction : CommonWithDbVerticleI { + override suspend fun withOptionalTransaction(block: suspend Unit.() -> T): T = + Unit.block() + + /* + // add some shortcuts, but too verbose in Kotlin with duplicate function names + override suspend fun Unit.selectWorld(id: Int): World = + invokeSelectWorld(id) + suspend fun invokeSelectWorld(id: Int): World = + selectWorld(id) + suspend fun selectWorld(id: Int): World + */ + } +} + +abstract class CommonWithDbVerticle : CommonVerticle(), + CommonWithDbVerticleI { + private lateinit var _dbClient: DbClient + val dbClient: DbClient get() = _dbClient + override val random = Random(0) + + override suspend fun start() { + _dbClient = initDbClient() + super.start() + } + + abstract suspend fun initDbClient(): DbClient + + fun HttpServerRequest.getQueries(): Int { + val queriesParam: String? = getParam("queries") + return queriesParam?.toIntOrNull()?.coerceIn(1, 500) ?: 1 + } + + override fun Router.routes() { + get("/db").jsonResponseCoHandler(Serializers.world) { + withOptionalTransaction { + selectRandomWorld() + } + } + + get("/queries").jsonResponseCoHandler(Serializers.worlds) { + val queries = it.request().getQueries() + withOptionalTransaction { + selectRandomWorlds(queries) + } + } + + get("/fortunes").coHandlerUnconfined { + val fortunes = mutableListOf() + withOptionalTransaction { + selectFortunesInto(fortunes) + } + + fortunes.add(Fortune(0, "Additional fortune added at request time.")) + fortunes.sortBy { it.message } + + val htmlString = buildString { + append("") + appendHTML(false).html { + head { + title("Fortunes") + } + body { + table { + tr { + th { +"id" } + th { +"message" } + } + for (fortune in fortunes) + tr { + td { +fortune.id.toString() } + td { +fortune.message } + } + } + } + } + } + + it.response().run { + headers().run { + addCommonHeaders() + add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textHtmlCharsetUtf8) + } + end(htmlString)/*.coAwait()*/ + } + } + + // Some changes to this part in the `vertx` portion in #9142 are not ported. + get("/updates").jsonResponseCoHandler(Serializers.worlds) { + val queries = it.request().getQueries() + withOptionalTransaction { + val worlds = selectRandomWorlds(queries) + val updatedWorlds = worlds.map { it.copy(randomNumber = random.nextIntBetween1And10000()) } + + // Approach 1 + // The updated worlds need to be sorted first to avoid deadlocks. + updateSortedWorlds(updatedWorlds.sortedBy { it.id }) + + /* + // Approach 2, worse performance + updatedWorlds.map { + pgPool.preparedQuery(UPDATE_WORLD_SQL).execute(Tuple.of(it.randomNumber, it.id)) + }.awaitAll() + */ + + updatedWorlds + } + } + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/database/ConnectionCommon.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/database/ConnectionCommon.kt new file mode 100644 index 00000000000..2415a703473 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/database/ConnectionCommon.kt @@ -0,0 +1,6 @@ +package database + +const val HOST = "tfb-database" +const val USER = "benchmarkdbuser" +const val PASSWORD = "benchmarkdbpass" +const val DATABASE = "hello_world" diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/database/Sqls.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/database/Sqls.kt new file mode 100644 index 00000000000..8d77166d970 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/common/src/main/kotlin/database/Sqls.kt @@ -0,0 +1,5 @@ +package database + +const val SELECT_WORLD_SQL = "SELECT id, randomnumber FROM world WHERE id = $1" +const val UPDATE_WORLD_SQL = "UPDATE world SET randomnumber = $1 WHERE id = $2" +const val SELECT_FORTUNE_SQL = "SELECT id, message FROM fortune" diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/build.gradle.kts new file mode 100644 index 00000000000..9b99f3ef711 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("buildlogic.kotlin-application-conventions") +} + +dependencies { + implementation(project(":with-db:with-db-common")) + + implementation(libs.vertx.pgClient) +} + +application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..c3cb517d3f3 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/Main.kt @@ -0,0 +1,6 @@ +suspend fun main() = + commonRunVertxServer( + "Vert.x-Web Kotlinx with database (PostgreSQL)", + {}, + { MainVerticle() } + ) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/MainVerticle.kt new file mode 100644 index 00000000000..b39a7e83b83 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/MainVerticle.kt @@ -0,0 +1,49 @@ +import database.* +import io.vertx.kotlin.coroutines.coAwait +import io.vertx.kotlin.pgclient.pgConnectOptionsOf +import io.vertx.pgclient.PgConnection +import io.vertx.sqlclient.PreparedQuery +import io.vertx.sqlclient.Row +import io.vertx.sqlclient.RowSet +import io.vertx.sqlclient.Tuple + +// `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s. +class MainVerticle : CommonWithDbVerticle(), + CommonWithDbVerticleI.ParallelOrPipelinedSelectWorlds, + CommonWithDbVerticleI.WithoutTransaction { + lateinit var selectWorldQuery: PreparedQuery> + lateinit var selectFortuneQuery: PreparedQuery> + lateinit var updateWorldQuery: PreparedQuery> + + override suspend fun initDbClient(): PgConnection = + // Parameters are copied from the "vertx-web" and "vertx" portions. + PgConnection.connect( + vertx, + pgConnectOptionsOf( + database = DATABASE, + host = HOST, + user = USER, + password = PASSWORD, + cachePreparedStatements = true, + pipeliningLimit = 256 + ) + ).coAwait().apply { + selectWorldQuery = preparedQuery(SELECT_WORLD_SQL) + selectFortuneQuery = preparedQuery(SELECT_FORTUNE_SQL) + updateWorldQuery = preparedQuery(UPDATE_WORLD_SQL) + } + + + override suspend fun Unit.selectWorld(id: Int) = + selectWorldQuery.execute(Tuple.of(id)).coAwait() + .single().toWorld() + + override suspend fun Unit.selectFortunesInto(fortunes: MutableList) { + selectFortuneQuery.execute().coAwait() + .mapTo(fortunes) { it.toFortune() } + } + + override suspend fun Unit.updateSortedWorlds(sortedWorlds: List) { + updateWorldQuery.executeBatch(sortedWorlds.map { Tuple.of(it.randomNumber, it.id) }).coAwait() + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/database/Row.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/database/Row.kt new file mode 100644 index 00000000000..b98c4938c7f --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/default/src/main/kotlin/database/Row.kt @@ -0,0 +1,11 @@ +package database + +import Fortune +import World +import io.vertx.sqlclient.Row + +fun Row.toWorld() = + World(getInteger(0), getInteger(1)) + +fun Row.toFortune() = + Fortune(getInteger(0), getString(1)) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/build.gradle.kts new file mode 100644 index 00000000000..f523d9f976a --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("buildlogic.kotlin-library-conventions") +} + +dependencies { + implementation(project(":with-db:with-db-common")) + + api(libs.exposed.core) + // explicitly made `implementation` instead of `api` to avoid importing wrong APIs in dependent projects + implementation(libs.exposed.jdbc) + implementation(libs.exposed.r2dbc) +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/src/main/kotlin/database/Queries.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/src/main/kotlin/database/Queries.kt new file mode 100644 index 00000000000..57ea0825a0d --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/src/main/kotlin/database/Queries.kt @@ -0,0 +1,20 @@ +package database + +import Fortune +import World +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.select as jdbcSelect +import org.jetbrains.exposed.v1.r2dbc.select as r2dbcSelect + +fun jdbcSelectWorldWithIdQuery(id: Int) = + WorldTable.jdbcSelect(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) + +fun r2dbcSelectWorldWithIdQuery(id: Int) = + WorldTable.r2dbcSelect(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) + +fun ResultRow.toWorld() = + World(this[WorldTable.id].value, this[WorldTable.randomNumber]) + +fun ResultRow.toFortune() = + Fortune(this[FortuneTable.id].value, this[FortuneTable.message]) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/src/main/kotlin/database/Tables.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/src/main/kotlin/database/Tables.kt new file mode 100644 index 00000000000..8978d986edd --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-common/src/main/kotlin/database/Tables.kt @@ -0,0 +1,17 @@ +package database + +import org.jetbrains.exposed.v1.core.dao.id.IdTable + +// see "toolset/databases/postgres/create-postgres.sql" + +object WorldTable : IdTable("world") { + override val id = integer("id").entityId() + + // The name is "randomNumber" in "create-postgres.sql" but it's actually "randomnumber" in the test database. + val randomNumber = integer("randomnumber").default(0) +} + +object FortuneTable : IdTable("fortune") { + override val id = integer("id").entityId() + val message = varchar("message", 2048) +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/build.gradle.kts new file mode 100644 index 00000000000..50b87f17f76 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("buildlogic.kotlin-application-conventions") +} + +dependencies { + implementation(project(":with-db:with-db-common")) + implementation(project(":with-db:r2dbc-common")) + implementation(project(":with-db:exposed-common")) + + implementation(libs.exposed.r2dbc) +} + +application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..65883ae3044 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/Main.kt @@ -0,0 +1,37 @@ +import database.r2dbcConnectPool + +suspend fun main(args: Array) { + // Parse CLI arguments + val isSharedPool = args.getOrNull(0)?.toBooleanStrictOrNull() ?: false + val poolSize = args.getOrNull(1)?.toIntOrNull() ?: 8 + val useKtorR2dbcConfig = args.getOrNull(2)?.toBooleanStrictOrNull() ?: false + + val benchmarkName = buildString { + append("Vert.x-Web Kotlinx with Exposed R2DBC (and PostgreSQL)") + if (!isSharedPool || poolSize != 512 || !useKtorR2dbcConfig) { + append(" - ") + if (isSharedPool) { + append("Shared Pool Size $poolSize") + } else { + append("Separate Pool Size $poolSize") + } + if (useKtorR2dbcConfig) { + append(" Ktor R2DBC portion config") + } + } + } + + if (isSharedPool) { + commonRunVertxServer( + benchmarkName, + { r2dbcConnectPool(poolSize, useKtorR2dbcConfig) }, + ::MainVerticle + ) + } else { + commonRunVertxServer( + benchmarkName, + { Unit }, + { MainVerticleWithSeparatePool(poolSize, useKtorR2dbcConfig) } + ) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/MainVerticle.kt new file mode 100644 index 00000000000..a64da227639 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/MainVerticle.kt @@ -0,0 +1,56 @@ +import database.* +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.single +import kotlinx.coroutines.flow.toList +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase +import org.jetbrains.exposed.v1.r2dbc.R2dbcTransaction +import org.jetbrains.exposed.v1.r2dbc.select +import org.jetbrains.exposed.v1.r2dbc.statements.toExecutable +import org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction + +/* +`ParallelOrPipelinedSelectWorlds` results in `io.r2dbc.postgresql.client.ReactorNettyClient$RequestQueueException: [08006] Cannot exchange messages because the request queue limit is exceeded`. +https://github.com/pgjdbc/r2dbc-postgresql/issues/360#issuecomment-869422327 offers a workaround, but it doesn't seem like the officially recommended approach. +The PostgreSQL R2DBC driver doesn't seem to have full support for pipelining and multiplexing as discussed in https://github.com/pgjdbc/r2dbc-postgresql/pull/28. + */ +class MainVerticle(private val r2dbcDatabase: R2dbcDatabase) : CommonWithDbVerticle(), + CommonWithDbVerticleI.SequentialSelectWorlds { + override suspend fun initDbClient(): R2dbcDatabase = + r2dbcDatabase + + override val httpServerStrictThreadMode get() = false + //override val coHandlerCoroutineContext: CoroutineContext get() = EmptyCoroutineContext + + // copied and adapted from https://github.com/huanshankeji/FrameworkBenchmarks/blob/34532d12439d95c939bde1044a5f11afd07927d1/frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt#L148-L185 + + override suspend fun withOptionalTransaction(block: suspend R2dbcTransaction.() -> T): T = + suspendTransaction(dbClient) { block() } + + override suspend fun R2dbcTransaction.selectWorld(id: Int): World = + r2dbcSelectWorldWithIdQuery(id).single().toWorld() + + override suspend fun R2dbcTransaction.updateSortedWorlds(sortedWorlds: List) { + val batch = BatchUpdateStatement(WorldTable) + sortedWorlds.forEach { world -> + batch.addBatch(EntityID(world.id, WorldTable)) + batch[WorldTable.randomNumber] = world.randomNumber + } + batch.toExecutable().execute(this) + } + + override suspend fun R2dbcTransaction.selectFortunesInto(fortunes: MutableList) { + FortuneTable.select(FortuneTable.id, FortuneTable.message) + .map { it.toFortune() }.toList(fortunes) + } +} + +// Factory functions for creating R2dbcDatabase instances with different configurations + +/** + * Creates a MainVerticle that will create its own connection pool per verticle instance. + * Used for separate-pool benchmark configurations. + */ +fun MainVerticleWithSeparatePool(poolSize: Int, useKtorR2dbcConfig: Boolean): MainVerticle = + MainVerticle(r2dbcConnectPool(poolSize, useKtorR2dbcConfig)) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/database/ExposedDatabaseR2dbc.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/database/ExposedDatabaseR2dbc.kt new file mode 100644 index 00000000000..7a9f578acf6 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-r2dbc/src/main/kotlin/database/ExposedDatabaseR2dbc.kt @@ -0,0 +1,26 @@ +package database + +import org.jetbrains.exposed.v1.core.vendors.PostgreSQLDialect +import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase +import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig + +// Configuration variants for benchmarking +fun r2dbcDatabaseConnectPoolOriginal(connectionPoolSize: Int) = + R2dbcDatabase.connect(connectionPoolOriginal(connectionPoolSize), R2dbcDatabaseConfig { + explicitDialect = PostgreSQLDialect() + }) + +fun r2dbcDatabaseConnectPoolKtorR2dbc(connectionPoolSize: Int) = + R2dbcDatabase.connect(connectionPoolKtorR2dbc(connectionPoolSize), R2dbcDatabaseConfig { + explicitDialect = PostgreSQLDialect() + }) + +/** + * Creates a shared R2dbcDatabase instance with a connection pool. + * Used for shared-pool benchmark configurations. + */ +fun r2dbcConnectPool(poolSize: Int, useKtorR2dbcConfig: Boolean): R2dbcDatabase = + if (useKtorR2dbcConfig) + r2dbcDatabaseConnectPoolKtorR2dbc(poolSize) + else + r2dbcDatabaseConnectPoolOriginal(poolSize) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/README.md b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/README.md new file mode 100644 index 00000000000..09975fb9916 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/README.md @@ -0,0 +1,32 @@ +# Exposed Vert.x SQL Client Benchmarking Test + +Adapted from the [`vertx-web-kotlinx` portion](../default) for the [Exposed Vert.x SQL Client](https://github.com/huanshankeji/exposed-vertx-sql-client) library. + +### Test Type Implementation Source Code + +* [DB](src/main/kotlin/MainVerticle.kt) +* [QUERY](src/main/kotlin/MainVerticle.kt) +* [UPDATE](src/main/kotlin/MainVerticle.kt) +* [FORTUNES](src/main/kotlin/MainVerticle.kt) + +## Important Libraries +The tests were run with: +* [Those in the `vertx-web-kotlinx` portion](../../README.md#important-libraries) +* [Exposed Vert.x SQL Client](https://github.com/huanshankeji/exposed-vertx-sql-client) + +## Test URLs +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?queries= + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/build.gradle.kts new file mode 100644 index 00000000000..8b83ce56e0f --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("buildlogic.kotlin-application-conventions") +} + +repositories { + mavenLocal() // for snapshot dependencies +} + +dependencies { + implementation(project(":with-db:with-db-common")) + implementation(project(":with-db:exposed-common")) + + implementation(libs.vertx.pgClient) // explicitly added to keep the version aligned + implementation(libs.exposedVertxSqlClient.core) + implementation(libs.exposedVertxSqlClient.postgresql) +} + +application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..45a4b1032e9 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/Main.kt @@ -0,0 +1,11 @@ +import com.huanshankeji.exposedvertxsqlclient.ExperimentalEvscApi +import com.huanshankeji.exposedvertxsqlclient.postgresql.exposed.exposedDatabaseConnectPostgresql +import database.connectionConfig + +@OptIn(ExperimentalEvscApi::class) +suspend fun main() = + commonRunVertxServer( + "Vert.x-Web Kotlinx with Exposed Vert.x SQL Client (and PostgreSQL)", + { connectionConfig.exposedDatabaseConnectPostgresql() }, + ::MainVerticle + ) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/MainVerticle.kt new file mode 100644 index 00000000000..337eb8f9c01 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/MainVerticle.kt @@ -0,0 +1,54 @@ +import com.huanshankeji.exposedvertxsqlclient.DatabaseClient +import com.huanshankeji.exposedvertxsqlclient.ExperimentalEvscApi +import com.huanshankeji.exposedvertxsqlclient.JdbcTransactionExposedTransactionProvider +import com.huanshankeji.exposedvertxsqlclient.postgresql.PgDatabaseClientConfig +import com.huanshankeji.exposedvertxsqlclient.postgresql.vertx.pgclient.createPgConnection +import database.* +import io.vertx.pgclient.PgConnection +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.statements.buildStatement +import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.select + +@OptIn(ExperimentalEvscApi::class) +class MainVerticle(val exposedDatabase: Database) : CommonWithDbVerticle, Unit>(), + CommonWithDbVerticleI.ParallelOrPipelinedSelectWorlds, Unit>, + CommonWithDbVerticleI.WithoutTransaction> { + // kept in case we support generating and reusing `PreparedQuery` + /* + lateinit var selectWorldQuery: PreparedQuery> + lateinit var selectFortuneQuery: PreparedQuery> + lateinit var updateWorldQuery: PreparedQuery> + */ + + override suspend fun initDbClient(): DatabaseClient { + // Parameters are copied from the "vertx-web" and "vertx" portions. + val pgConnection = createPgConnection(vertx, connectionConfig, { + cachePreparedStatements = true + pipeliningLimit = 256 + }) + return DatabaseClient( + pgConnection, + PgDatabaseClientConfig(JdbcTransactionExposedTransactionProvider(exposedDatabase), validateBatch = false) + ) + } + + override suspend fun Unit.selectWorld(id: Int): World = + dbClient.executeQuery(jdbcSelectWorldWithIdQuery(id)) + .single().toWorld() + + override suspend fun Unit.updateSortedWorlds(sortedWorlds: List) { + dbClient.executeBatchUpdate(sortedWorlds.map { world -> + buildStatement { + WorldTable.update({ WorldTable.id eq world.id }) { + it[randomNumber] = world.randomNumber + } + } + }) + } + + override suspend fun Unit.selectFortunesInto(fortunes: MutableList) { + dbClient.executeQuery(with(FortuneTable) { select(id, message) }) + .mapTo(fortunes) { it.toFortune() } + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/database/ConnectionConfig.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/database/ConnectionConfig.kt new file mode 100644 index 00000000000..8aeef01e6bd --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/exposed-vertx-sql-client/src/main/kotlin/database/ConnectionConfig.kt @@ -0,0 +1,10 @@ +package database + +import com.huanshankeji.exposedvertxsqlclient.ConnectionConfig + +val connectionConfig = ConnectionConfig.Socket( + host = HOST, + user = USER, + password = PASSWORD, + database = DATABASE +) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/build.gradle.kts new file mode 100644 index 00000000000..b85841b479b --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("buildlogic.kotlin-library-conventions") +} + +dependencies { + implementation(project(":with-db:with-db-common")) + + api(libs.r2dbc.spi) + implementation(libs.r2dbc.postgresql) + api(libs.r2dbc.pool) +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/src/main/kotlin/database/R2dbcKtorR2dbc.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/src/main/kotlin/database/R2dbcKtorR2dbc.kt new file mode 100644 index 00000000000..310468bc966 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/src/main/kotlin/database/R2dbcKtorR2dbc.kt @@ -0,0 +1,35 @@ +package database + +import io.r2dbc.pool.ConnectionPool +import io.r2dbc.pool.ConnectionPoolConfiguration +import io.r2dbc.postgresql.PostgresqlConnectionConfiguration +import io.r2dbc.postgresql.PostgresqlConnectionFactory +import io.r2dbc.postgresql.client.SSLMode +import io.r2dbc.spi.ConnectionFactory +import java.time.Duration + +// Alternative configurations copied from the `ktor-r2dbc` portion. These configurations don't lead to better performance as tested in Continuous Benchmarking. + +val connectionFactoryKtorR2dbc: ConnectionFactory = PostgresqlConnectionFactory( + PostgresqlConnectionConfiguration.builder() + .host(HOST) + .port(5432) + .database(DATABASE) + .username(USER) + .password(PASSWORD) + .sslMode(SSLMode.DISABLE) + .tcpKeepAlive(true) + .tcpNoDelay(true) + .build() +) + +fun connectionPoolConfigurationKtorR2dbc(size: Int) = + ConnectionPoolConfiguration.builder(connectionFactoryKtorR2dbc) + .initialSize(size) + .maxSize(size) + .maxIdleTime(Duration.ofSeconds(30)) + .maxAcquireTime(Duration.ofSeconds(5)) + .build() + +fun connectionPoolKtorR2dbc(size: Int) = + ConnectionPool(connectionPoolConfigurationKtorR2dbc(size)) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/src/main/kotlin/database/R2dbcOriginal.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/src/main/kotlin/database/R2dbcOriginal.kt new file mode 100644 index 00000000000..e64c0494e53 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc-common/src/main/kotlin/database/R2dbcOriginal.kt @@ -0,0 +1,27 @@ +package database + +import io.r2dbc.pool.ConnectionPool +import io.r2dbc.pool.ConnectionPoolConfiguration +import io.r2dbc.spi.ConnectionFactories +import io.r2dbc.spi.ConnectionFactoryOptions +import io.r2dbc.spi.ConnectionFactoryOptions.DRIVER + +// Original configuration before optimizations +val connectionFactoryOriginal = ConnectionFactories.get( + ConnectionFactoryOptions.builder() + .option(DRIVER, "postgresql") + .option(ConnectionFactoryOptions.HOST, HOST) + .option(ConnectionFactoryOptions.USER, USER) + .option(ConnectionFactoryOptions.PASSWORD, PASSWORD) + .option(ConnectionFactoryOptions.DATABASE, DATABASE) + .build() +) + +fun connectionPoolConfigurationOriginal(size: Int) = + ConnectionPoolConfiguration.builder(connectionFactoryOriginal) + .initialSize(size) + .maxSize(size) + .build() + +fun connectionPoolOriginal(size: Int) = + ConnectionPool(connectionPoolConfigurationOriginal(size)) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/build.gradle.kts new file mode 100644 index 00000000000..90612fe81e8 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("buildlogic.kotlin-application-conventions") +} + +dependencies { + implementation(project(":with-db:with-db-common")) + implementation(project(":with-db:r2dbc-common")) + + implementation(libs.kotlinx.coroutines.reactive) +} + +application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..d0cb31ef561 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/Main.kt @@ -0,0 +1,48 @@ +import database.connectionPoolKtorR2dbc +import database.connectionPoolOriginal +import io.r2dbc.spi.ConnectionFactory + +suspend fun main(args: Array) { + // Parse CLI arguments + val isSharedPool = args.getOrNull(0)?.toBooleanStrictOrNull() ?: false + val poolSize = args.getOrNull(1)?.toIntOrNull() + ?: 8 // TODO `1` might produce equivalent results because there is no transaction in this portion compared to `exposed-r2dbc`. + val useKtorR2dbcConfig = args.getOrNull(2)?.toBooleanStrictOrNull() ?: false + + val benchmarkName = buildString { + append("Vert.x-Web Kotlinx with R2DBC (and PostgreSQL)") + if (!isSharedPool || poolSize != 512 || !useKtorR2dbcConfig) { + append(" - ") + if (isSharedPool) { + append("Shared Pool Size $poolSize") + } else { + append("Separate Pool Size $poolSize") + } + if (useKtorR2dbcConfig) { + append(" Ktor R2DBC portion config") + } + } + } + + if (isSharedPool) { + // Shared pool: create one ConnectionPool that all verticles will share + val connectionFactory: ConnectionFactory = if (useKtorR2dbcConfig) { + connectionPoolKtorR2dbc(poolSize) + } else { + connectionPoolOriginal(poolSize) + } + + commonRunVertxServer( + benchmarkName, + {}, + { MainVerticle(connectionFactory) } + ) + } else { + // Separate pool: each verticle creates its own pool + commonRunVertxServer( + benchmarkName, + {}, + { MainVerticleWithSeparatePool(poolSize, useKtorR2dbcConfig) } + ) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/MainVerticle.kt new file mode 100644 index 00000000000..71dc99b3279 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/MainVerticle.kt @@ -0,0 +1,66 @@ +import database.* +import io.r2dbc.spi.Connection +import io.r2dbc.spi.ConnectionFactory +import io.r2dbc.spi.Readable +import kotlinx.coroutines.reactive.awaitFirst +import kotlinx.coroutines.reactive.awaitSingle +import kotlinx.coroutines.reactive.collect + +/* +`ParallelOrPipelinedSelectWorlds` leads to `io.r2dbc.postgresql.client.ReactorNettyClient$RequestQueueException: [08006] Cannot exchange messages because the request queue limit is exceeded`. +https://github.com/pgjdbc/r2dbc-postgresql/issues/360#issuecomment-869422327 offers a workaround, but it doesn't seem like the officially recommended approach. +The PostgreSQL R2DBC driver doesn't seem to have full support for pipelining and multiplexing as discussed in https://github.com/pgjdbc/r2dbc-postgresql/pull/28. + */ +class MainVerticle(private val connectionFactory: ConnectionFactory) : CommonWithDbVerticle(), + CommonWithDbVerticleI.SequentialSelectWorlds, + CommonWithDbVerticleI.WithoutTransaction { + override suspend fun initDbClient(): Connection = + connectionFactory.create().awaitSingle() + + override suspend fun stop() { + dbClient.close().awaitSingle() + } + + override val httpServerStrictThreadMode get() = false + //override val coHandlerCoroutineContext: CoroutineContext get() = EmptyCoroutineContext + + override suspend fun Unit.selectWorld(id: Int): World = + dbClient.createStatement(SELECT_WORLD_SQL).bind(0, id).execute() + .awaitSingle() + .map(Readable::toWorld) + .awaitSingle() + + override suspend fun Unit.updateSortedWorlds(sortedWorlds: List) { + val statement = dbClient.createStatement(UPDATE_WORLD_SQL) + val lastIndex = sortedWorlds.lastIndex + sortedWorlds.forEachIndexed { index, world -> + statement.bind(0, world.randomNumber) + .bind(1, world.id) + if (index < lastIndex) statement.add() + } + // wait for the execution to complete + // For batch statements, execute() returns multiple Result objects. + // We must consume the rowsUpdated Publisher from each Result. + statement.execute().collect { result -> + result.rowsUpdated.awaitFirst() + } + } + + override suspend fun Unit.selectFortunesInto(fortunes: MutableList) { + dbClient.createStatement(SELECT_FORTUNE_SQL).execute() + .awaitSingle() + .map(Readable::toFortune) + //.asFlow().toList(fortunes) + .collect(fortunes::add) + } +} + +// Factory function for creating MainVerticle with separate connection pools +fun MainVerticleWithSeparatePool(poolSize: Int, useKtorR2dbcConfig: Boolean): MainVerticle { + val connectionPool = if (useKtorR2dbcConfig) { + connectionPoolKtorR2dbc(poolSize) + } else { + connectionPoolOriginal(poolSize) + } + return MainVerticle(connectionPool) +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/database/Row.kt b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/database/Row.kt new file mode 100644 index 00000000000..d24c7c1d660 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/with-db/r2dbc/src/main/kotlin/database/Row.kt @@ -0,0 +1,11 @@ +package database + +import Fortune +import World +import io.r2dbc.spi.Readable + +fun Readable.toWorld() = + World(get(0, Int::class.java)!!, get(1, Int::class.java)!!) + +fun Readable.toFortune() = + Fortune(get(0, Int::class.java)!!, get(1, String::class.java)!!) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/build.gradle.kts new file mode 100644 index 00000000000..69ba9858f6f --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("buildlogic.kotlin-application-conventions") +} + +dependencies { + implementation(project(":common")) +} + +application.mainClass.set("MainKt") diff --git a/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..e47623e282c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/src/main/kotlin/Main.kt @@ -0,0 +1,6 @@ +suspend fun main() = + commonRunVertxServer( + "Vert.x-Web Kotlinx", + {}, + { MainVerticle() } + ) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/src/main/kotlin/MainVerticle.kt b/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/src/main/kotlin/MainVerticle.kt new file mode 100644 index 00000000000..97c52d778f7 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/without-db/default/src/main/kotlin/MainVerticle.kt @@ -0,0 +1,20 @@ +import io.vertx.core.http.HttpHeaders +import io.vertx.ext.web.Router + +class MainVerticle : CommonVerticle() { + override fun Router.routes() { + get("/json").jsonResponseCoHandler(Serializers.message) { + Message("Hello, World!") + } + + get("/plaintext").coHandlerUnconfined { + it.response().run { + headers().run { + addCommonHeaders() + add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.textPlain) + } + end("Hello, World!")/*.coAwait()*/ + } + } + } +} \ No newline at end of file diff --git a/frameworks/OCaml/morph/.dockerignore b/frameworks/OCaml/morph/.dockerignore deleted file mode 100644 index ac1cfa6c94b..00000000000 --- a/frameworks/OCaml/morph/.dockerignore +++ /dev/null @@ -1,6 +0,0 @@ -_esy -node_modules -_opam -_build -**/_build -**/_opam diff --git a/frameworks/OCaml/morph/README.md b/frameworks/OCaml/morph/README.md deleted file mode 100755 index d32154cc940..00000000000 --- a/frameworks/OCaml/morph/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Morph Benchmarking Test - -### Test Type Implementation Source Code - -* [JSON](./src/bin/Json_handler.re) -* [PLAINTEXT](./src/bin/Json_handler.re) -* [DB](./src/bin/Db_handler.re) -* [QUERY](./src/bin/Query_handler.re) - - -## Important Libraries -The tests were run with: -* [Morph](https://github.com/reason-native-web/morph) -* [ diff --git a/frameworks/OCaml/morph/benchmark_config.json b/frameworks/OCaml/morph/benchmark_config.json deleted file mode 100755 index 5b2fe87f60a..00000000000 --- a/frameworks/OCaml/morph/benchmark_config.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "framework": "morph", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Morph", - "language": "OCaml", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Morph", - "notes": "", - "versus": "None", - "tags": ["broken"] - }, - "flambda": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Morph", - "language": "OCaml", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Morph-flambda", - "notes": "", - "versus": "None", - "tags": ["broken"] - }, - "single": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Morph", - "language": "OCaml", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Morph-single-process", - "notes": "This is using a single process since that is more realistic", - "versus": "None", - "tags": ["broken"] - } - } - ] -} diff --git a/frameworks/OCaml/morph/config.toml b/frameworks/OCaml/morph/config.toml deleted file mode 100644 index 7860b673223..00000000000 --- a/frameworks/OCaml/morph/config.toml +++ /dev/null @@ -1,50 +0,0 @@ -[framework] -name = "morph" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "None" - -[single] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "None" - -[flambda] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/OCaml/morph/morph-flambda.dockerfile b/frameworks/OCaml/morph/morph-flambda.dockerfile deleted file mode 100644 index 698c30dfe01..00000000000 --- a/frameworks/OCaml/morph/morph-flambda.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ocurrent/opam:alpine-3.12-ocaml-4.11-flambda - -# https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html -# https://linux.die.net/man/1/ocamlrun -# https://blog.janestreet.com/memory-allocator-showdown/ -ENV OCAMLRUNPARAM a=2,o=240 - -RUN sudo apk update && sudo apk add openssl-dev && \ - opam depext dune conf-libev httpaf httpaf-lwt-unix lwt yojson conf-postgresql conf-libffi - -COPY src/morph-tfb.opam src/dune-project src/morph-tfb.opam.template ./ - -RUN opam install --yes --deps-only . - -COPY ./src/bin ./bin -COPY ./src/server_io ./server_io -COPY ./src/server_io_single ./server_io_single -COPY ./src/server_io_nproc ./server_io_nproc - -ENV SERVER_IO=NPROC - -RUN sudo chown -R opam ./bin && sudo chown -R opam ./server_* -RUN opam exec -- dune build --profile release bin/tfb.exe - -EXPOSE 8080 - -ENTRYPOINT _build/default/bin/tfb.exe diff --git a/frameworks/OCaml/morph/morph-single.dockerfile b/frameworks/OCaml/morph/morph-single.dockerfile deleted file mode 100644 index 54797c7e93d..00000000000 --- a/frameworks/OCaml/morph/morph-single.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ocurrent/opam:alpine-3.12-ocaml-4.11 - -# https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html -# https://linux.die.net/man/1/ocamlrun -# https://blog.janestreet.com/memory-allocator-showdown/ -ENV OCAMLRUNPARAM a=2,o=240 - -RUN sudo apk update && sudo apk add openssl-dev && \ - opam depext dune conf-libev httpaf httpaf-lwt-unix lwt yojson conf-postgresql conf-libffi - -COPY src/morph-tfb.opam src/dune-project src/morph-tfb.opam.template ./ - -RUN opam install --yes --deps-only . - -COPY ./src/bin ./bin -COPY ./src/server_io ./server_io -COPY ./src/server_io_single ./server_io_single -COPY ./src/server_io_nproc ./server_io_nproc - -ENV SERVER_IO=SINGLE - -RUN sudo chown -R opam ./bin && sudo chown -R opam ./server_* -RUN opam exec -- dune build --profile release bin/tfb.exe - -EXPOSE 8080 - -ENTRYPOINT _build/default/bin/tfb.exe diff --git a/frameworks/OCaml/morph/morph.dockerfile b/frameworks/OCaml/morph/morph.dockerfile deleted file mode 100644 index a754ba7cd5f..00000000000 --- a/frameworks/OCaml/morph/morph.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ocurrent/opam:alpine-3.12-ocaml-4.11 - -# https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html -# https://linux.die.net/man/1/ocamlrun -# https://blog.janestreet.com/memory-allocator-showdown/ -ENV OCAMLRUNPARAM a=2,o=240 - -RUN sudo apk update && sudo apk add openssl-dev && \ - opam depext dune conf-libev httpaf httpaf-lwt-unix lwt yojson conf-postgresql conf-libffi - -COPY src/morph-tfb.opam src/dune-project src/morph-tfb.opam.template ./ - -RUN opam install --yes --deps-only . - -COPY ./src/bin ./bin -COPY ./src/server_io ./server_io -COPY ./src/server_io_single ./server_io_single -COPY ./src/server_io_nproc ./server_io_nproc - -ENV SERVER_IO=NPROC - -RUN sudo chown -R opam ./bin && sudo chown -R opam ./server_* -RUN opam exec -- dune build --profile release bin/tfb.exe - -EXPOSE 8080 - -ENTRYPOINT _build/default/bin/tfb.exe diff --git a/frameworks/OCaml/morph/src/.gitignore b/frameworks/OCaml/morph/src/.gitignore deleted file mode 100644 index 6a42f1a779f..00000000000 --- a/frameworks/OCaml/morph/src/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.merlin -!bin/ diff --git a/frameworks/OCaml/morph/src/bin/Caqti.ml b/frameworks/OCaml/morph/src/bin/Caqti.ml deleted file mode 100644 index e79c235ca6a..00000000000 --- a/frameworks/OCaml/morph/src/bin/Caqti.ml +++ /dev/null @@ -1,85 +0,0 @@ -module Archi = struct - let start () = - let connection_url = - "postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?connect_timeout=15" - in - Caqti_lwt.connect_pool ~max_size:10 (Uri.of_string connection_url) - |> Result.map_error Caqti_error.show - |> Lwt.return - - let stop - (pool : (Caqti_lwt.connection, [> Caqti_error.connect ]) Caqti_lwt.Pool.t) - = - Logs.info (fun m -> m "Disconnecting from database"); - Caqti_lwt.Pool.drain pool - - let component : - ( unit, - (Caqti_lwt.connection, [ | Caqti_error.t ]) Caqti_lwt.Pool.t ) - Archi_lwt.Component.t = - Archi_lwt.Component.make ~start ~stop -end - -module Query = struct - type ('res, 'err) query_result = - ('res, ([> Caqti_error.call_or_retrieve ] as 'err)) result Lwt.t - - type ('res, 'err) query = Caqti_lwt.connection -> ('res, 'err) query_result - - let get_world : id:int -> (Models.world, 'err) query = - let open Models in - [%rapper - get_one - {sql| - SELECT @int{id}, @int{randomNumber} FROM World - WHERE id = %int{id} - |sql} - record_out] - - let get_fortunes : unit -> (Models.fortune list, 'err) query = - let open Models in - [%rapper - get_many - {sql| - SELECT @int{id}, @string{message} FROM Fortune - |sql} - record_out] - - let update_random_number : random_number:int -> id:int -> (unit, 'err) query = - [%rapper - execute - {sql| - UPDATE World - SET randomNumber = %int{random_number} - WHERE id = %int{id} - |sql}] -end - -module Middleware = struct - module Env = struct - let key = Hmap.Key.create () - end - - let get_db (request : Morph.Request.t) = Hmap.get Env.key request.ctx - - let use request query = - let pool = get_db request in - Caqti_lwt.Pool.use query pool - - let get_world request (id : int) : (Models.world, string) Lwt_result.t = - use request (Query.get_world ~id) |> Lwt_result.map_err Caqti_error.show - - let get_fortunes request : (Models.fortune list, string) Lwt_result.t = - use request (Query.get_fortunes ()) |> Lwt_result.map_err Caqti_error.show - - let update_random_number request ~random_number id : - (unit, string) Lwt_result.t = - use request (Query.update_random_number ~random_number ~id) - |> Lwt_result.map_err Caqti_error.show - - let middleware ~db (handler : Morph.Server.handler) - (request : Morph.Request.t) = - let ctx = Hmap.add Env.key db request.ctx in - let next_request = { request with ctx } in - handler next_request -end diff --git a/frameworks/OCaml/morph/src/bin/Caqti.mli b/frameworks/OCaml/morph/src/bin/Caqti.mli deleted file mode 100644 index 628d954d978..00000000000 --- a/frameworks/OCaml/morph/src/bin/Caqti.mli +++ /dev/null @@ -1,36 +0,0 @@ -module Archi : sig - val start : - unit -> - ( (Caqti_lwt.connection, [> Caqti_error.connect ]) Caqti_lwt.Pool.t, - string ) - result - Lwt.t - - val stop : - (Caqti_lwt.connection, [> Caqti_error.connect ]) Caqti_lwt.Pool.t -> - unit Lwt.t - - val component : - ( unit, - (Caqti_lwt.connection, Caqti_error.t) Caqti_lwt.Pool.t ) - Archi_lwt.Component.t -end - -module Middleware : sig - val use : - Morph.Request.t -> - ((module Caqti_lwt.CONNECTION) -> ('a, Caqti_error.t) Lwt_result.t) -> - ('a, Caqti_error.t) Lwt_result.t - - val get_world : Morph.Request.t -> int -> (Models.world, string) Lwt_result.t - - val get_fortunes : - Morph.Request.t -> (Models.fortune list, string) Lwt_result.t - - val update_random_number : - Morph.Request.t -> random_number:int -> int -> (unit, string) result Lwt.t - - val middleware : - db:((module Caqti_lwt.CONNECTION), Caqti_error.t) Caqti_lwt.Pool.t -> - Morph.Server.middleware -end diff --git a/frameworks/OCaml/morph/src/bin/Handlers.re b/frameworks/OCaml/morph/src/bin/Handlers.re deleted file mode 100644 index b2a60f04628..00000000000 --- a/frameworks/OCaml/morph/src/bin/Handlers.re +++ /dev/null @@ -1,70 +0,0 @@ -let random_int = () => Random.int(10000) + 1; - -let text = _req => { - Morph.Response.text("Hello, World!") |> Lwt.return; -}; - -let json: Morph.Server.handler = - _req => { - let json = `Assoc([("message", `String("Hello, World!"))]); - Yojson.Safe.to_string(json) |> Morph.Response.json |> Lwt.return; - }; - -let db = req => { - open Lwt_result.Infix; - let id = random_int(); - Caqti.Middleware.get_world(req, id) - |> Lwt_result.map_err(e => `Server(e)) - >>= ( - (Models.{id, randomNumber}) => { - `Assoc([("id", `Int(id)), ("randomNumber", `Int(randomNumber))]) - |> Yojson.Safe.to_string - |> Morph.Response.json - |> Lwt.return; - } - ); -}; - -let queries = (count, req: Morph.Request.t) => { - open Lwt.Syntax; - - let query_ids = List.init(count, _ => random_int()); - - let+ worlds_json = - List.map( - id => { - let+ result = Caqti.Middleware.get_world(req, id); - switch (result) { - | Error(_) => failwith("failed to query") - | Ok(Models.{id, randomNumber}) => - `Assoc([("id", `Int(id)), ("randomNumber", `Int(randomNumber))]) - }; - }, - query_ids, - ) - |> Lwt.all; - - let json_string = Yojson.Safe.to_string(`List(worlds_json)); - Morph.Response.json(json_string); -}; - -let respond_html = elt => { - Morph.Response.html(Format.asprintf("%a", Tyxml.Html.pp(), elt)); -}; - -let fortunes = req => { - open Lwt.Syntax; - let+ result = Caqti.Middleware.get_fortunes(req); - - let additional_fortune = - Models.{id: 0, message: "Additional fortune added at request time."}; - - switch (result) { - | Ok(fortunes) => - [additional_fortune, ...fortunes] - |> List.sort(Models.compare_fortune) - |> View.fortunes_page - |> respond_html - | Error(str) => Error(`Server(str)) - }; -}; diff --git a/frameworks/OCaml/morph/src/bin/Handlers.rei b/frameworks/OCaml/morph/src/bin/Handlers.rei deleted file mode 100644 index 51a3c6b7d80..00000000000 --- a/frameworks/OCaml/morph/src/bin/Handlers.rei +++ /dev/null @@ -1,9 +0,0 @@ -let text: Morph.Server.handler; - -let json: Morph.Server.handler; - -let db: Morph.Server.handler; - -let queries: int => Morph.Server.handler; - -let fortunes: Morph.Server.handler; diff --git a/frameworks/OCaml/morph/src/bin/Headers_middleware.ml b/frameworks/OCaml/morph/src/bin/Headers_middleware.ml deleted file mode 100644 index 1d534ae1a80..00000000000 --- a/frameworks/OCaml/morph/src/bin/Headers_middleware.ml +++ /dev/null @@ -1,38 +0,0 @@ -let weekday_to_string = function - | `Mon -> "Mon" - | `Tue -> "Tue" - | `Wed -> "Wed" - | `Thu -> "Thu" - | `Fri -> "Fri" - | `Sat -> "Sat" - | `Sun -> "Sun" - -let month_to_string = function - | 1 -> "Jan" - | 2 -> "Feb" - | 3 -> "Mar" - | 4 -> "Apr" - | 5 -> "May" - | 6 -> "Jun" - | 7 -> "Jul" - | 8 -> "Aug" - | 9 -> "Sep" - | 10 -> "Oct" - | 11 -> "Nov" - | 12 -> "Dec" - | _ -> failwith "month" - -let timestamp now = - let weekday_str = weekday_to_string (Ptime.weekday now) in - let (year, month, day), ((hour, minute, second), _) = - Ptime.to_date_time now - in - let month_str = month_to_string month in - Printf.sprintf "%s, %02u %s %04u %02u:%02u:%02u GMT" weekday_str day month_str - year hour minute second - -let make (handler : Morph.Server.handler) request = - let open Lwt.Infix in - handler request - >|= Morph.Response.add_headers - [ ("Date", timestamp (Ptime_clock.now ())); ("Server", "Morph") ] diff --git a/frameworks/OCaml/morph/src/bin/Logger.ml b/frameworks/OCaml/morph/src/bin/Logger.ml deleted file mode 100644 index 9bf55f5479b..00000000000 --- a/frameworks/OCaml/morph/src/bin/Logger.ml +++ /dev/null @@ -1,57 +0,0 @@ -(*---------------------------------------------------------------------------- - * Copyright (c) 2019-2020, António Nuno Monteiro - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*) - -(* The following snippet is borrowed from https://github.com/anmonteiro/piaf/blob/master/bin/carl.ml *) - -let setup_log ?style_renderer level = - let pp_header src ppf (l, h) = - if l = Logs.App then Format.fprintf ppf "%a" Logs_fmt.pp_header (l, h) - else - let x = - match Array.length Sys.argv with - | 0 -> Filename.basename Sys.executable_name - | _n -> Filename.basename Sys.argv.(0) - in - let x = - if Logs.Src.equal src Logs.default then x else Logs.Src.name src - in - Format.fprintf ppf "%s: %a " x Logs_fmt.pp_header (l, h) - in - let format_reporter = - let report src = - let { Logs.report } = Logs_fmt.reporter ~pp_header:(pp_header src) () in - report src - in - { Logs.report } - in - Fmt_tty.setup_std_outputs ?style_renderer (); - Logs.set_level ~all:true level; - Logs.set_reporter format_reporter diff --git a/frameworks/OCaml/morph/src/bin/Models.ml b/frameworks/OCaml/morph/src/bin/Models.ml deleted file mode 100644 index 5fa7cbeee62..00000000000 --- a/frameworks/OCaml/morph/src/bin/Models.ml +++ /dev/null @@ -1,5 +0,0 @@ -type world = { id : int; randomNumber : int } - -type fortune = { id : int; message : string } - -let compare_fortune a b = String.compare a.message b.message diff --git a/frameworks/OCaml/morph/src/bin/Morph_wrapper.ml b/frameworks/OCaml/morph/src/bin/Morph_wrapper.ml deleted file mode 100644 index 1483c1f9471..00000000000 --- a/frameworks/OCaml/morph/src/bin/Morph_wrapper.ml +++ /dev/null @@ -1,7 +0,0 @@ -let client_address_key : Unix.sockaddr Hmap.key = Hmap.Key.create () - -let wrap_context (next : Morph.Server.handler) - (req : Unix.sockaddr Piaf.Server.ctx) = - let open Lwt.Infix in - let ctx = Hmap.add client_address_key req.ctx Hmap.empty in - next { req with ctx } >|= Morph.Response.response_of_result diff --git a/frameworks/OCaml/morph/src/bin/Router.ml b/frameworks/OCaml/morph/src/bin/Router.ml deleted file mode 100644 index 3f82ed4c010..00000000000 --- a/frameworks/OCaml/morph/src/bin/Router.ml +++ /dev/null @@ -1,35 +0,0 @@ -let json_route : (Morph.Server.handler, 'a) Routes.target = - Routes.(s "json" /? nil) - -let plaintext_route : (Morph.Server.handler, 'a) Routes.target = - Routes.(s "plaintext" /? nil) - -let db_route : (Morph.Server.handler, 'a) Routes.target = Routes.(s "db" /? nil) - -let query_route_missing : (Morph.Server.handler, 'a) Routes.target = - Routes.(s "queries" //? nil) - -let query_route_int = Routes.(s "queries" / int /? nil) - -let query_route_str = Routes.(s "queries" / str /? nil) - -let fortunes_route = Routes.(s "fortunes" /? nil) - -let not_found_handler _request = Morph.Response.not_found () |> Lwt.return - -let routes = - Routes. - [ - json_route @--> Handlers.json; - plaintext_route @--> Handlers.text; - db_route @--> Handlers.db; - query_route_missing @--> Handlers.queries 1; - (query_route_int @--> function - | queries when queries > 500 -> Handlers.queries 500 - | queries when queries < 1 -> Handlers.queries 1 - | queries -> Handlers.queries queries); - (query_route_str @--> fun _ -> Handlers.queries 1); - fortunes_route @--> Handlers.fortunes; - ] - -let handler = Morph.Router.make ~get:routes ~print:true ~not_found_handler () diff --git a/frameworks/OCaml/morph/src/bin/View.re b/frameworks/OCaml/morph/src/bin/View.re deleted file mode 100644 index fd11e000564..00000000000 --- a/frameworks/OCaml/morph/src/bin/View.re +++ /dev/null @@ -1,34 +0,0 @@ -open Tyxml; - -module FortuneRow = { - let createElement = (~fortune: Models.fortune, ()) => { - - {Html.txt(string_of_int(fortune.id))} - {Html.txt(fortune.message)} - ; - }; -}; - -module FortunesTable = { - let table_header = "id" "message" ; - - let createElement = (~fortunes: list(Models.fortune), ()) => { - let table_content: - Html.list_wrap(Html.elt([< Html_types.table_content_fun])) = [ - table_header, - ...List.map(fortune => , fortunes), - ]; - Html.table(table_content); - }; -}; - -module Layout = { - let createElement = (~title, ~children, ()) => - - {Html.txt(title)} - ...children - ; -}; - -let fortunes_page = fortunes => - ; diff --git a/frameworks/OCaml/morph/src/bin/dune b/frameworks/OCaml/morph/src/bin/dune deleted file mode 100644 index 44866c0ec33..00000000000 --- a/frameworks/OCaml/morph/src/bin/dune +++ /dev/null @@ -1,28 +0,0 @@ -(* -*- tuareg -*- *) - -let server_io = - match Sys.getenv_opt "SERVER_IO" with - | Some "NPROC" -> "server_io_nproc" - | Some "SINGLE" -> "server_io_single" - | _ -> "server_io_single" - -let () = Jbuild_plugin.V1.send @@ {| -(executable - (name tfb) - (public_name tfb) - (ocamlopt_flags - (:standard -O3 -unbox-closures)) - (libraries caqti caqti-lwt caqti-driver-postgresql lwt logs logs.fmt fmt.tty - morph archi archi-lwt routes yojson ptime ptime.clock ptime.clock.os - ppx_rapper.runtime tyxml - |} ^ server_io ^ {|) - (preprocess - (pps ppx_rapper tyxml-jsx))) - -(env - (docker - (flags - (:standard -ccopt -static -I /usr/include -I /usr/lib -cclib -lldap -cclib - -lcrypto -cclib -lssl -cclib -lpq -cclib -lpgport -cclib -lpgcommon - -cclib -lev)))) -|} diff --git a/frameworks/OCaml/morph/src/bin/tfb.re b/frameworks/OCaml/morph/src/bin/tfb.re deleted file mode 100644 index e4983610724..00000000000 --- a/frameworks/OCaml/morph/src/bin/tfb.re +++ /dev/null @@ -1,86 +0,0 @@ -let error_handler = (_client_addr, ~request as _=?, ~respond, err) => { - let error_to_string = - fun - | `Bad_gateway => "Bad gateway" - | `Bad_request => "Bad request" - | `Exn(_exn) => "Unhandled server error" - | `Internal_server_error => "Internal server error"; - - let error_handler = - respond( - ~headers=Piaf.Headers.of_list([("connection", "close")]), - Piaf.Body.of_string(error_to_string(err)), - ); - - Lwt.return(error_handler); -}; - -module WebServer = { - let start = ((), db) => { - let port = - switch (Sys.getenv_opt("PORT")) { - | Some(p) => int_of_string(p) - | None => 8080 - }; - - Logs.app(m => m("Starting server on %n", port)); - - let request_handler = - Headers_middleware.make( - Caqti.Middleware.middleware(~db, Router.handler), - ) - |> Morph_wrapper.wrap_context; - Server_io.listen(~request_handler, ~error_handler, port) - |> Lwt_result.return; - }; - - let stop = _server => { - Logs.info(m => m("Stopped Server")) |> Lwt.return; - }; - - let component: Archi_lwt.Component.t(unit, unit) = - Archi_lwt.Component.using( - ~start, - ~stop, - ~dependencies=[Caqti.Archi.component], - ); -}; - -let system = - Archi_lwt.System.make([ - ("database", Caqti.Archi.component), - ("web_server", WebServer.component), - ]); - -let main = () => { - open Lwt.Infix; - Logger.setup_log(Some(Logs.Warning)); - - Archi_lwt.System.start((), system) - >|= ( - fun - | Ok(system) => { - Logs.info(m => m("Starting")); - - Sys.( - set_signal( - sigint, - Signal_handle( - _ => { - Logs.err(m => m("SIGNINT received, tearing down.@.")); - Archi_lwt.System.stop(system) |> ignore; - }, - ), - ) - ); - } - | Error(error) => { - Logs.err(m => m("ERROR: %s@.", error)); - exit(1); - } - ); -}; - -Lwt_engine.set((new Lwt_engine.libev)()); - -let () = Lwt_main.run(main()); diff --git a/frameworks/OCaml/morph/src/dune-project b/frameworks/OCaml/morph/src/dune-project deleted file mode 100644 index 28e58465a9b..00000000000 --- a/frameworks/OCaml/morph/src/dune-project +++ /dev/null @@ -1,35 +0,0 @@ -(lang dune 2.6) - -(name morph-tfb) - -(generate_opam_files true) - -(authors "Ulrik Strid") - -(maintainers "ulrik.strid@outlook.com") - -(package - (name morph-tfb) - (synopsis "Framework Benchmark for Morph") - (depends - (ocaml - (>= 4.11.0)) - archi - archi-lwt - caqti-driver-postgresql - caqti - caqti-lwt - conf-libev - dune - fmt - logs - lwt - routes - uri - yojson - morph - piaf - reason - tyxml - tyxml-jsx - ppx_rapper)) diff --git a/frameworks/OCaml/morph/src/esy.json b/frameworks/OCaml/morph/src/esy.json deleted file mode 100644 index da6afde49ca..00000000000 --- a/frameworks/OCaml/morph/src/esy.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "morph-tfb", - "version": "0.0.0", - "description": "Benchmarks for morph", - "esy": { - "build": ["dune build -p #{self.name}"], - "buildDev": "dune build --root=. --promote-install-file" - }, - "scripts": { - "start": "redemon -p ./src dune exec src/tfb.exe", - "test": "dune runtest --no-buffer", - "watch:test": "redemon -p ./oidc -p ./oidc-client -p ./test esy x RunTests.exe", - "docs": "dune build @doc --root .", - "fmt": "dune build @fmt --auto-promote --root .", - "docs-path": "esy echo #{self.target_dir / 'default' / '_doc' / '_html' / 'index.html'}" - }, - "dependencies": { - "@esy-ocaml/reason": "^3.6.2", - "@opam/archi": "*", - "@opam/archi-lwt": "*", - "@opam/caqti": "^1.2.0", - "@opam/caqti-lwt": "^1.2.0", - "@opam/caqti-driver-postgresql": "^1.2.0", - "@opam/dune": "^2.5.0", - "@opam/fmt": "*", - "@opam/logs": "*", - "@opam/lwt": "^5.0.0", - "@opam/routes": "*", - "@opam/uri": "*", - "@opam/yojson": "*", - "@reason-native-web/morph": "^0.6.1", - "@reason-native-web/piaf": "^1.4.0", - "@reason-native-web/esy-openssl": "^1.1.1006", - "@opam/conf-libev": "esy-packages/libev:package.json#0b5eb6685b688649045aceac55dc559f6f21b829", - "ocaml": "~4.10.0" - }, - "devDependencies": { - "@opam/merlin": "*", - "@opam/ocaml-lsp-server": "ocaml/ocaml-lsp:ocaml-lsp-server.opam", - "@opam/ocamlformat": "*" - }, - "resolutions": { - "@reason-native-web/morph": "reason-native-web/morph:morph.json#c7bdd60dbfb99eccd4ce27559117919455061e0e", - "@opam/caqti": "paurkedal/ocaml-caqti:caqti.opam#4a09a3f5fab4f15c90f1cf1790688f6e6bb94185", - "@opam/conf-postgresql": "ulrikstrid/postgresql:package.json#193d72af7f2132e30ad429401232da6359b248a2", - "@opam/conf-pkg-config": "esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79", - "@opam/session": "inhabitedtype/ocaml-session:session.opam#6180413" - } -} diff --git a/frameworks/OCaml/morph/src/morph-tfb.opam b/frameworks/OCaml/morph/src/morph-tfb.opam deleted file mode 100644 index 90cfcfe8617..00000000000 --- a/frameworks/OCaml/morph/src/morph-tfb.opam +++ /dev/null @@ -1,51 +0,0 @@ -# This file is generated by dune, edit dune-project instead -opam-version: "2.0" -synopsis: "Framework Benchmark for Morph" -maintainer: ["ulrik.strid@outlook.com"] -authors: ["Ulrik Strid"] -depends: [ - "ocaml" {>= "4.11.0"} - "archi" - "archi-lwt" - "caqti-driver-postgresql" - "caqti" - "caqti-lwt" - "conf-libev" - "dune" {>= "2.6"} - "fmt" - "logs" - "lwt" - "routes" - "uri" - "yojson" - "morph" - "piaf" - "reason" - "tyxml" - "tyxml-jsx" - "ppx_rapper" -] -build: [ - ["dune" "subst"] {pinned} - [ - "dune" - "build" - "-p" - name - "-j" - jobs - "@install" - "@runtest" {with-test} - "@doc" {with-doc} - ] -] -pin-depends: [ - [ "reason.dev" "git+https://github.com/facebook/reason#master"] - [ "piaf.dev" "git+https://github.com/anmonteiro/piaf.git#master" ] - [ "httpaf.dev" "git+https://github.com/anmonteiro/httpaf.git#fork" ] - [ "httpaf-lwt.dev" "git+https://github.com/anmonteiro/httpaf.git#fork" ] - [ "httpaf-lwt-unix.dev" "git+https://github.com/anmonteiro/httpaf.git#fork" ] - [ "ssl.dev" "git+https://github.com/savonet/ocaml-ssl.git#6b75fac" ] - [ "morph.dev" "git+https://github.com/reason-native-web/morph.git#master" ] - [ "session.dev" "git+https://github.com/inhabitedtype/ocaml-session.git#master" ] -] diff --git a/frameworks/OCaml/morph/src/morph-tfb.opam.template b/frameworks/OCaml/morph/src/morph-tfb.opam.template deleted file mode 100644 index 0975720bdd4..00000000000 --- a/frameworks/OCaml/morph/src/morph-tfb.opam.template +++ /dev/null @@ -1,10 +0,0 @@ -pin-depends: [ - [ "reason.dev" "git+https://github.com/facebook/reason#master"] - [ "piaf.dev" "git+https://github.com/anmonteiro/piaf.git#master" ] - [ "httpaf.dev" "git+https://github.com/anmonteiro/httpaf.git#fork" ] - [ "httpaf-lwt.dev" "git+https://github.com/anmonteiro/httpaf.git#fork" ] - [ "httpaf-lwt-unix.dev" "git+https://github.com/anmonteiro/httpaf.git#fork" ] - [ "ssl.dev" "git+https://github.com/savonet/ocaml-ssl.git#6b75fac" ] - [ "morph.dev" "git+https://github.com/reason-native-web/morph.git#master" ] - [ "session.dev" "git+https://github.com/inhabitedtype/ocaml-session.git#master" ] -] diff --git a/frameworks/OCaml/morph/src/server_io/dune b/frameworks/OCaml/morph/src/server_io/dune deleted file mode 100644 index 74a63f73c30..00000000000 --- a/frameworks/OCaml/morph/src/server_io/dune +++ /dev/null @@ -1,6 +0,0 @@ -(library - (name server_io) - (libraries lwt lwt.unix piaf unix) - (modules server_io) - (virtual_modules server_io) - (default_implementation server_io_single)) diff --git a/frameworks/OCaml/morph/src/server_io/server_io.mli b/frameworks/OCaml/morph/src/server_io/server_io.mli deleted file mode 100644 index 583aadf7d5b..00000000000 --- a/frameworks/OCaml/morph/src/server_io/server_io.mli +++ /dev/null @@ -1,11 +0,0 @@ -val listen : request_handler:Unix.sockaddr Piaf.Server.Handler.t -> - error_handler:(Unix.sockaddr -> - ?request:Piaf.Request.t -> - respond:(headers:Piaf.Headers.t -> - Piaf.Body.t -> Piaf.Server.Error_response.t) -> - [ `Bad_gateway - | `Bad_request - | `Exn of exn - | `Internal_server_error ] -> - Piaf.Server.Error_response.t Lwt.t) -> - int -> unit diff --git a/frameworks/OCaml/morph/src/server_io_nproc/dune b/frameworks/OCaml/morph/src/server_io_nproc/dune deleted file mode 100644 index 507e238a0a0..00000000000 --- a/frameworks/OCaml/morph/src/server_io_nproc/dune +++ /dev/null @@ -1,4 +0,0 @@ -(library - (name server_io_nproc) - (implements server_io) - (libraries lwt lwt.unix piaf unix)) diff --git a/frameworks/OCaml/morph/src/server_io_nproc/server_io.ml b/frameworks/OCaml/morph/src/server_io_nproc/server_io.ml deleted file mode 100644 index 9d062359b8a..00000000000 --- a/frameworks/OCaml/morph/src/server_io_nproc/server_io.ml +++ /dev/null @@ -1,195 +0,0 @@ -(* This code is borrowed from this PR: https://github.com/anmonteiro/piaf/pull/80 *) -open Lwt.Infix - -type server = { shutdown: unit Lwt.t Lazy.t } - -let dump_lwt () = - let options = - [ "fd_passing", `fd_passing - ; "fdatasync", `fdatasync - ; "get_affinity", `get_affinity - ; "get_cpu", `get_cpu - ; "get_credentials", `get_credentials - ; "libev", `libev - ; "madvise", `madvise - ; "mincore", `mincore - ; "recv_msg", `recv_msg - ; "send_msg", `send_msg - ; "set_affinity", `set_affinity - ; "wait4", `wait4 - ] - in - Format.eprintf "Lwt:\n%a@." - (Format.pp_print_list - ~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n") - (fun fmt (str, opt) -> Format.fprintf fmt " %s = %b" str (Lwt_sys.have opt))) - options - -let close_socket fd = - Lwt.finalize - (fun () -> - Lwt.catch - (fun () -> - Lwt_unix.shutdown fd Unix.SHUTDOWN_ALL; - Lwt.return_unit) - (function - (* Occurs if the peer closes the connection first. *) - | Unix.Unix_error (Unix.ENOTCONN, _, _) -> Lwt.return_unit - | exn -> Lwt.fail exn)) - (fun () -> - Lwt_unix.close fd) - -let establish_server_generic - ?fd:preexisting_socket_for_listening - listening_address - connection_handler_callback = - - let listening_socket = - match preexisting_socket_for_listening with - | None -> - Lwt_unix.socket - (Unix.domain_of_sockaddr listening_address) Unix.SOCK_STREAM 0 - | Some socket -> - socket - in - Lwt_unix.setsockopt listening_socket Unix.SO_REUSEADDR true; - - (* This promise gets resolved with `Should_stop when the user calls - Lwt_io.shutdown_server. This begins the shutdown procedure. *) - let should_stop, notify_should_stop = - Lwt.wait () in - - (* Some time after Lwt_io.shutdown_server is called, this function - establish_server_generic will actually close the listening socket. At that - point, this promise is resolved. This ends the shutdown procedure. *) - let wait_until_listening_socket_closed, notify_listening_socket_closed = - Lwt.wait () in - - let rec accept_loop () = - let try_to_accept = - Lwt_unix.accept listening_socket >|= fun x -> - `Accepted x - in - - Lwt.pick [try_to_accept; should_stop] >>= function - | `Accepted (client_socket, client_address) -> - begin - try Lwt_unix.set_close_on_exec client_socket - with Invalid_argument _ -> () - end; - - connection_handler_callback client_address client_socket; - - accept_loop () - - | `Should_stop -> - Lwt_unix.close listening_socket >>= fun () -> - - begin match listening_address with - | Unix.ADDR_UNIX path when path <> "" && path.[0] <> '\x00' -> - Unix.unlink path - | _ -> - () - end [@ocaml.warning "-4"]; - - Lwt.wakeup_later notify_listening_socket_closed (); - Lwt.return_unit - in - - let server = - {shutdown = - lazy begin - Lwt.wakeup_later notify_should_stop `Should_stop; - wait_until_listening_socket_closed - end} - in - - (* Actually start the server. *) - let server_has_started = - (* bind_function listening_socket listening_address >>= fun () -> *) - (* Lwt_unix.listen listening_socket backlog; *) - - Lwt.async accept_loop; - - Lwt.return_unit - in - - server, server_has_started - -let establish_server_with_client_socket - ?server_fd ?(no_close = false) sockaddr f - = - let handler client_address client_socket = - Lwt.async (fun () -> - (* Not using Lwt.finalize here, to make sure that exceptions from [f] - reach !Lwt.async_exception_hook before exceptions from closing the - channels. *) - Lwt.catch - (fun () -> f client_address client_socket) - (fun exn -> - !Lwt.async_exception_hook exn; - Lwt.return_unit) - >>= fun () -> - if no_close then - Lwt.return_unit - else if Lwt_unix.state client_socket = Lwt_unix.Closed then - Lwt.return_unit - else - Lwt.catch - (fun () -> close_socket client_socket) - (fun exn -> - !Lwt.async_exception_hook exn; - Lwt.return_unit)) - in - let server, server_started = - establish_server_generic - ?fd:server_fd - sockaddr - handler - in - server_started >>= fun () -> Lwt.return server - - -let listen ~request_handler ~error_handler port = - let nproc = - Unix.open_process_in "getconf _NPROCESSORS_ONLN" - |> input_line - |> int_of_string - in - Format.eprintf "Detected %d cores@." nproc; - let ulimit_n = - Unix.open_process_in "ulimit -n" |> input_line |> int_of_string - in - Format.eprintf "Detected %d max open files@." ulimit_n; - dump_lwt (); - let sockaddr = Unix.(ADDR_INET (inet_addr_any, port)) in - let socket = - Lwt_unix.socket (Unix.domain_of_sockaddr sockaddr) Unix.SOCK_STREAM 0 - in - Lwt_unix.setsockopt socket Unix.SO_REUSEADDR true; - Lwt_main.run - @@ ( Lwt_unix.bind socket sockaddr >|= fun () -> - Lwt_unix.listen socket 10_000 ); - for i = 1 to nproc do - flush_all (); - let pid = Lwt_unix.fork () in - if pid = 0 then ( - (* child *) - (Lwt.async_exception_hook := fun exn -> raise exn); - Lwt.async (fun () -> - establish_server_with_client_socket - ~server_fd:socket - sockaddr - (Piaf.Server.create ?config:None ~error_handler request_handler) - >|= fun _server -> - Format.eprintf "Listening on localhost:%i (child %d)@." port i); - let forever, _ = Lwt.wait () in - Lwt_main.run forever; - exit 0) - done; - while true do - Unix.pause () - done - -let listen ~request_handler ~error_handler port = - Unix.handle_unix_error (listen ~request_handler ~error_handler) port diff --git a/frameworks/OCaml/morph/src/server_io_single/dune b/frameworks/OCaml/morph/src/server_io_single/dune deleted file mode 100644 index f3aa973c73e..00000000000 --- a/frameworks/OCaml/morph/src/server_io_single/dune +++ /dev/null @@ -1,4 +0,0 @@ -(library - (name server_io_single) - (implements server_io) - (libraries lwt lwt.unix piaf unix)) diff --git a/frameworks/OCaml/morph/src/server_io_single/server_io.ml b/frameworks/OCaml/morph/src/server_io_single/server_io.ml deleted file mode 100644 index 0f189f469b8..00000000000 --- a/frameworks/OCaml/morph/src/server_io_single/server_io.ml +++ /dev/null @@ -1,10 +0,0 @@ -let listen ~request_handler ~error_handler port = - let open Lwt.Infix in - let listen_address = Unix.(ADDR_INET (inet_addr_any, port)) in - Lwt.async (fun () -> - Lwt_io.establish_server_with_client_socket listen_address - (Piaf.Server.create ?config:None ~error_handler request_handler) - >|= fun _server -> - Printf.printf "Listening on port %i and echoing POST requests.\n%!" port); - let forever, _ = Lwt.wait () in - Lwt_main.run forever diff --git a/frameworks/PHP/README.md b/frameworks/PHP/README.md index 5950f883f6c..7fd46c01cfe 100644 --- a/frameworks/PHP/README.md +++ b/frameworks/PHP/README.md @@ -63,10 +63,13 @@ upgrading the framework version in the future. ### PHP Experts -_There aren't any PHP experts listed, yet. If you're an expert, -add yourself!_ +@joanhey + +If you're an expert, add yourself! ### Resources & Interesting Links +https://github.com/myaaghubi/PHP-Frameworks-Bench + _If you find some interesting links related to the PHP tests, add them here._ diff --git a/frameworks/PHP/cakephp/composer.json b/frameworks/PHP/cakephp/composer.json index bbcb4956fc2..3e2441ff5ed 100644 --- a/frameworks/PHP/cakephp/composer.json +++ b/frameworks/PHP/cakephp/composer.json @@ -5,11 +5,11 @@ "type": "project", "license": "MIT", "require": { - "php": ">=8.1", - "cakephp/cakephp": "^5.0.1", + "php": ">=8.2", + "cakephp/cakephp": "^5.3.0", "cakephp/migrations": "^4.0.0", "cakephp/plugin-installer": "^2.0", - "mobiledetect/mobiledetectlib": "^3.74" + "mobiledetect/mobiledetectlib": "^4.8.03" }, "require-dev": { "cakephp/bake": "^3.0.0", diff --git a/frameworks/PHP/cakephp/config/app.php b/frameworks/PHP/cakephp/config/app.php index 100a98e873a..9a5870a8d09 100644 --- a/frameworks/PHP/cakephp/config/app.php +++ b/frameworks/PHP/cakephp/config/app.php @@ -107,9 +107,9 @@ * Duration will be set to '+2 minutes' in bootstrap.php when debug = true * If you set 'className' => 'Null' core cache will be disabled. */ - '_cake_core_' => [ + '_cake_translations_' => [ 'className' => FileEngine::class, - 'prefix' => 'myapp_cake_core_', + 'prefix' => 'myapp_cake_translations_', 'path' => CACHE . 'persistent' . DS, 'serialize' => true, 'duration' => '+1 years', diff --git a/frameworks/PHP/codeigniter/README.md b/frameworks/PHP/codeigniter/README.md index 617f6098124..6f45a4200a6 100644 --- a/frameworks/PHP/codeigniter/README.md +++ b/frameworks/PHP/codeigniter/README.md @@ -1,33 +1,17 @@ -# Codeigniter PHP Benchmarking Test +# Codeigniter Benchmarking Test -This is the Codeigniter PHP portion of a [benchmarking test suite](../) comparing a variety of web development platforms. +This is the Codeigniter portion of a [benchmarking test suite](../../../) comparing a variety of web development platforms. -### JSON Encoding Test -Uses the PHP standard [JSON encoder](http://www.php.net/manual/en/function.json-encode.php). - -* [JSON test controller](app/Controllers/Bench.php) +### Plaintext and JSON Encoding Test +Implemented as functions right in [app/Config/Routes.php](app/Config/Routes.php). ### Data-Store/Database Mapping Test -Uses the db abstraction class from Codeigniter - -* [DB test controller](app/Controllers/Bench.php) - - -## Infrastructure Software Versions -The tests were run with: -* [Codeigniter Version 4](https://www.codeigniter.com) +Implemented in two variants: +- ORM based in file [app/Controllers/Full.php](app/Controllers/Full.php) +- Plain SQL based in file [app/Controllers/Raw.php](app/Controllers/Raw.php) ## Test URLs -### JSON Encoding Test - -http://localhost/json - -### Data-Store/Database Mapping Test - -http://localhost/db -### Variable Query Test - -http://localhost/queries/2 +See [benchmark_config.json](benchmark_config.json) for mapping tests to URLs. diff --git a/frameworks/PHP/codeigniter/app/Config/App.php b/frameworks/PHP/codeigniter/app/Config/App.php index 7beb46646f1..b761da772ad 100644 --- a/frameworks/PHP/codeigniter/app/Config/App.php +++ b/frameworks/PHP/codeigniter/app/Config/App.php @@ -14,7 +14,7 @@ class App extends BaseConfig * URL to your CodeIgniter root. Typically, this will be your base URL, * WITH a trailing slash: * - * http://example.com/ + * E.g., http://example.com/ */ public string $baseURL = 'http://localhost:8080/'; @@ -22,13 +22,12 @@ class App extends BaseConfig * Allowed Hostnames in the Site URL other than the hostname in the baseURL. * If you want to accept multiple Hostnames, set this. * - * E.g. When your site URL ($baseURL) is 'http://example.com/', and your site - * also accepts 'http://media.example.com/' and - * 'http://accounts.example.com/': - * ['media.example.com', 'accounts.example.com'] + * E.g., + * When your site URL ($baseURL) is 'http://example.com/', and your site + * also accepts 'http://media.example.com/' and 'http://accounts.example.com/': + * ['media.example.com', 'accounts.example.com'] * - * @var string[] - * @phpstan-var list + * @var list */ public array $allowedHostnames = []; @@ -37,9 +36,9 @@ class App extends BaseConfig * Index File * -------------------------------------------------------------------------- * - * Typically this will be your index.php file, unless you've renamed it to - * something else. If you are using mod_rewrite to remove the page set this - * variable so that it is blank. + * Typically, this will be your `index.php` file, unless you've renamed it to + * something else. If you have configured your web server to remove this file + * from your site URIs, set this variable to an empty string. */ public string $indexPage = 'index.php'; @@ -49,17 +48,41 @@ class App extends BaseConfig * -------------------------------------------------------------------------- * * This item determines which server global should be used to retrieve the - * URI string. The default setting of 'REQUEST_URI' works for most servers. + * URI string. The default setting of 'REQUEST_URI' works for most servers. * If your links do not seem to work, try one of the other delicious flavors: * - * 'REQUEST_URI' Uses $_SERVER['REQUEST_URI'] - * 'QUERY_STRING' Uses $_SERVER['QUERY_STRING'] - * 'PATH_INFO' Uses $_SERVER['PATH_INFO'] + * 'REQUEST_URI': Uses $_SERVER['REQUEST_URI'] + * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING'] + * 'PATH_INFO': Uses $_SERVER['PATH_INFO'] * * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded! */ public string $uriProtocol = 'REQUEST_URI'; + /* + |-------------------------------------------------------------------------- + | Allowed URL Characters + |-------------------------------------------------------------------------- + | + | This lets you specify which characters are permitted within your URLs. + | When someone tries to submit a URL with disallowed characters they will + | get a warning message. + | + | As a security measure you are STRONGLY encouraged to restrict URLs to + | as few characters as possible. + | + | By default, only these are allowed: `a-z 0-9~%.:_-` + | + | Set an empty string to allow all characters -- but only if you are insane. + | + | The configured value is actually a regular expression character group + | and it will be used as: '/\A[]+\z/iu' + | + | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! + | + */ + public string $permittedURIChars = 'a-z 0-9~%.:_\-'; + /** * -------------------------------------------------------------------------- * Default Locale @@ -95,7 +118,7 @@ class App extends BaseConfig * * IncomingRequest::setLocale() also uses this list. * - * @var string[] + * @var list */ public array $supportedLocales = ['en']; @@ -107,9 +130,10 @@ class App extends BaseConfig * The default timezone that will be used in your application to display * dates with the date helper, and can be retrieved through app_timezone() * - * @see https://www.php.net/manual/en/timezones.php for list of timezones supported by PHP. + * @see https://www.php.net/manual/en/timezones.php for list of timezones + * supported by PHP. */ - public string $appTimezone = 'America/Chicago'; + public string $appTimezone = 'UTC'; /** * -------------------------------------------------------------------------- @@ -131,7 +155,7 @@ class App extends BaseConfig * If true, this will force every request made to this application to be * made via a secure connection (HTTPS). If the incoming request is not * secure, the user will be redirected to a secure version of the page - * and the HTTP Strict Transport Security header will be set. + * and the HTTP Strict Transport Security (HSTS) header will be set. */ public bool $forceGlobalSecureRequests = false; diff --git a/frameworks/PHP/codeigniter/app/Config/Autoload.php b/frameworks/PHP/codeigniter/app/Config/Autoload.php index 22f05ecdab2..9a928241a0e 100644 --- a/frameworks/PHP/codeigniter/app/Config/Autoload.php +++ b/frameworks/PHP/codeigniter/app/Config/Autoload.php @@ -17,8 +17,6 @@ * * NOTE: This class is required prior to Autoloader instantiation, * and does not extend BaseConfig. - * - * @immutable */ class Autoload extends AutoloadConfig { @@ -30,23 +28,17 @@ class Autoload extends AutoloadConfig * their location on the file system. These are used by the autoloader * to locate files the first time they have been instantiated. * - * The '/app' and '/system' directories are already mapped for you. - * you may change the name of the 'App' namespace if you wish, + * The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are + * already mapped for you. + * + * You may change the name of the 'App' namespace if you wish, * but this should be done prior to creating any namespaced classes, * else you will need to modify all of those classes for this to work. * - * Prototype: - * $psr4 = [ - * 'CodeIgniter' => SYSTEMPATH, - * 'App' => APPPATH - * ]; - * - * @var array|string> - * @phpstan-var array> + * @var array|string> */ public $psr4 = [ - APP_NAMESPACE => APPPATH, // For custom app namespace - 'Config' => APPPATH . 'Config', + APP_NAMESPACE => APPPATH, ]; /** @@ -81,8 +73,7 @@ class Autoload extends AutoloadConfig * '/path/to/my/file.php', * ]; * - * @var string[] - * @phpstan-var list + * @var list */ public $files = []; @@ -95,8 +86,7 @@ class Autoload extends AutoloadConfig * 'form', * ]; * - * @var string[] - * @phpstan-var list + * @var list */ public $helpers = []; } diff --git a/frameworks/PHP/codeigniter/app/Config/Boot/development.php b/frameworks/PHP/codeigniter/app/Config/Boot/development.php deleted file mode 100644 index 05a861258fc..00000000000 --- a/frameworks/PHP/codeigniter/app/Config/Boot/development.php +++ /dev/null @@ -1,32 +0,0 @@ - + * @var array{storePath?: string, mode?: int} */ public array $file = [ 'storePath' => WRITEPATH . 'cache/', @@ -119,12 +89,13 @@ class Cache extends BaseConfig * ------------------------------------------------------------------------- * Memcached settings * ------------------------------------------------------------------------- + * * Your Memcached servers can be specified below, if you are using * the Memcached drivers. * * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached * - * @var array + * @var array{host?: string, port?: int, weight?: int, raw?: bool} */ public array $memcached = [ 'host' => '127.0.0.1', @@ -137,10 +108,11 @@ class Cache extends BaseConfig * ------------------------------------------------------------------------- * Redis settings * ------------------------------------------------------------------------- + * * Your Redis server can be specified below, if you are using * the Redis or Predis drivers. * - * @var array + * @var array{host?: string, password?: string|null, port?: int, timeout?: int, database?: int} */ public array $redis = [ 'host' => '127.0.0.1', @@ -158,8 +130,7 @@ class Cache extends BaseConfig * This is an array of cache engine alias' and class names. Only engines * that are listed here are allowed to be used. * - * @var array - * @phpstan-var array> + * @var array> */ public array $validHandlers = [ 'dummy' => DummyHandler::class, @@ -169,4 +140,23 @@ class Cache extends BaseConfig 'redis' => RedisHandler::class, 'wincache' => WincacheHandler::class, ]; + + /** + * -------------------------------------------------------------------------- + * Web Page Caching: Cache Include Query String + * -------------------------------------------------------------------------- + * + * Whether to take the URL query string into consideration when generating + * output cache files. Valid options are: + * + * false = Disabled + * true = Enabled, take all query parameters into account. + * Please be aware that this may result in numerous cache + * files generated for the same page over and over again. + * ['q'] = Enabled, but only take into account the specified list + * of query parameters. + * + * @var bool|list + */ + public $cacheQueryString = false; } diff --git a/frameworks/PHP/codeigniter/app/Config/Constants.php b/frameworks/PHP/codeigniter/app/Config/Constants.php index 47b92f83293..fb56bb1c5b0 100644 --- a/frameworks/PHP/codeigniter/app/Config/Constants.php +++ b/frameworks/PHP/codeigniter/app/Config/Constants.php @@ -77,18 +77,3 @@ defined('EXIT_DATABASE') || define('EXIT_DATABASE', 8); // database error defined('EXIT__AUTO_MIN') || define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code defined('EXIT__AUTO_MAX') || define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code - -/** - * @deprecated Use \CodeIgniter\Events\Events::PRIORITY_LOW instead. - */ -define('EVENT_PRIORITY_LOW', 200); - -/** - * @deprecated Use \CodeIgniter\Events\Events::PRIORITY_NORMAL instead. - */ -define('EVENT_PRIORITY_NORMAL', 100); - -/** - * @deprecated Use \CodeIgniter\Events\Events::PRIORITY_HIGH instead. - */ -define('EVENT_PRIORITY_HIGH', 10); diff --git a/frameworks/PHP/codeigniter/app/Config/ContentSecurityPolicy.php b/frameworks/PHP/codeigniter/app/Config/ContentSecurityPolicy.php index 7799c476f07..2ac41a70dad 100644 --- a/frameworks/PHP/codeigniter/app/Config/ContentSecurityPolicy.php +++ b/frameworks/PHP/codeigniter/app/Config/ContentSecurityPolicy.php @@ -45,28 +45,28 @@ class ContentSecurityPolicy extends BaseConfig /** * Will default to self if not overridden * - * @var string|string[]|null + * @var list|string|null */ public $defaultSrc; /** * Lists allowed scripts' URLs. * - * @var string|string[] + * @var list|string */ public $scriptSrc = 'self'; /** * Lists allowed stylesheets' URLs. * - * @var string|string[] + * @var list|string */ public $styleSrc = 'self'; /** * Defines the origins from which images can be loaded. * - * @var string|string[] + * @var list|string */ public $imageSrc = 'self'; @@ -75,14 +75,14 @@ class ContentSecurityPolicy extends BaseConfig * * Will default to self if not overridden * - * @var string|string[]|null + * @var list|string|null */ public $baseURI; /** * Lists the URLs for workers and embedded frame contents * - * @var string|string[] + * @var list|string */ public $childSrc = 'self'; @@ -90,21 +90,21 @@ class ContentSecurityPolicy extends BaseConfig * Limits the origins that you can connect to (via XHR, * WebSockets, and EventSource). * - * @var string|string[] + * @var list|string */ public $connectSrc = 'self'; /** * Specifies the origins that can serve web fonts. * - * @var string|string[] + * @var list|string */ public $fontSrc; /** * Lists valid endpoints for submission from `
` tags. * - * @var string|string[] + * @var list|string */ public $formAction = 'self'; @@ -114,7 +114,7 @@ class ContentSecurityPolicy extends BaseConfig * and `` tags. This directive can't be used in * `` tags and applies only to non-HTML resources. * - * @var string|string[]|null + * @var list|string|null */ public $frameAncestors; @@ -122,40 +122,40 @@ class ContentSecurityPolicy extends BaseConfig * The frame-src directive restricts the URLs which may * be loaded into nested browsing contexts. * - * @var array|string|null + * @var list|string|null */ public $frameSrc; /** * Restricts the origins allowed to deliver video and audio. * - * @var string|string[]|null + * @var list|string|null */ public $mediaSrc; /** * Allows control over Flash and other plugins. * - * @var string|string[] + * @var list|string */ public $objectSrc = 'self'; /** - * @var string|string[]|null + * @var list|string|null */ public $manifestSrc; /** * Limits the kinds of plugins a page may invoke. * - * @var string|string[]|null + * @var list|string|null */ public $pluginTypes; /** * List of actions allowed. * - * @var string|string[]|null + * @var list|string|null */ public $sandbox; diff --git a/frameworks/PHP/codeigniter/app/Config/Cookie.php b/frameworks/PHP/codeigniter/app/Config/Cookie.php index 84ccc0e99d8..3bad184797c 100644 --- a/frameworks/PHP/codeigniter/app/Config/Cookie.php +++ b/frameworks/PHP/codeigniter/app/Config/Cookie.php @@ -85,7 +85,7 @@ class Cookie extends BaseConfig * (empty string) means default SameSite attribute set by browsers (`Lax`) * will be set on cookies. If set to `None`, `$secure` must also be set. * - * @phpstan-var 'None'|'Lax'|'Strict'|'' + * @var ''|'Lax'|'None'|'Strict' */ public string $samesite = 'Lax'; diff --git a/frameworks/PHP/codeigniter/app/Config/Cors.php b/frameworks/PHP/codeigniter/app/Config/Cors.php new file mode 100644 index 00000000000..2b4edf6bf60 --- /dev/null +++ b/frameworks/PHP/codeigniter/app/Config/Cors.php @@ -0,0 +1,105 @@ +, + * allowedOriginsPatterns: list, + * supportsCredentials: bool, + * allowedHeaders: list, + * exposedHeaders: list, + * allowedMethods: list, + * maxAge: int, + * } + */ + public array $default = [ + /** + * Origins for the `Access-Control-Allow-Origin` header. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin + * + * E.g.: + * - ['http://localhost:8080'] + * - ['https://www.example.com'] + */ + 'allowedOrigins' => [], + + /** + * Origin regex patterns for the `Access-Control-Allow-Origin` header. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin + * + * NOTE: A pattern specified here is part of a regular expression. It will + * be actually `#\A\z#`. + * + * E.g.: + * - ['https://\w+\.example\.com'] + */ + 'allowedOriginsPatterns' => [], + + /** + * Weather to send the `Access-Control-Allow-Credentials` header. + * + * The Access-Control-Allow-Credentials response header tells browsers whether + * the server allows cross-origin HTTP requests to include credentials. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials + */ + 'supportsCredentials' => false, + + /** + * Set headers to allow. + * + * The Access-Control-Allow-Headers response header is used in response to + * a preflight request which includes the Access-Control-Request-Headers to + * indicate which HTTP headers can be used during the actual request. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers + */ + 'allowedHeaders' => [], + + /** + * Set headers to expose. + * + * The Access-Control-Expose-Headers response header allows a server to + * indicate which response headers should be made available to scripts running + * in the browser, in response to a cross-origin request. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers + */ + 'exposedHeaders' => [], + + /** + * Set methods to allow. + * + * The Access-Control-Allow-Methods response header specifies one or more + * methods allowed when accessing a resource in response to a preflight + * request. + * + * E.g.: + * - ['GET', 'POST', 'PUT', 'DELETE'] + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods + */ + 'allowedMethods' => [], + + /** + * Set how many seconds the results of a preflight request can be cached. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age + */ + 'maxAge' => 7200, + ]; +} diff --git a/frameworks/PHP/codeigniter/app/Config/Database.php b/frameworks/PHP/codeigniter/app/Config/Database.php index ed199c24eed..9ad71d8c5a5 100644 --- a/frameworks/PHP/codeigniter/app/Config/Database.php +++ b/frameworks/PHP/codeigniter/app/Config/Database.php @@ -10,19 +10,19 @@ class Database extends Config { /** - * The directory that holds the Migrations - * and Seeds directories. + * The directory that holds the Migrations and Seeds directories. */ public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR; /** - * Lets you choose which connection group to - * use if no other is specified. + * Lets you choose which connection group to use if no other is specified. */ public string $defaultGroup = 'default'; /** * The default database connection. + * + * @var array */ public array $default = [ 'DSN' => '', @@ -43,43 +43,11 @@ class Database extends Config 'failover' => [], 'port' => 3306, 'numberNative' => false, + 'foundRows' => false, + 'dateFormat' => [ + 'date' => 'Y-m-d', + 'datetime' => 'Y-m-d H:i:s', + 'time' => 'H:i:s', + ], ]; - - /** - * This database connection is used when - * running PHPUnit database tests. - */ - public array $tests = [ - 'DSN' => '', - 'hostname' => '127.0.0.1', - 'username' => '', - 'password' => '', - 'database' => ':memory:', - 'DBDriver' => 'SQLite3', - 'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS - 'pConnect' => false, - 'DBDebug' => true, - 'charset' => 'utf8', - 'DBCollat' => 'utf8_general_ci', - 'swapPre' => '', - 'encrypt' => false, - 'compress' => false, - 'strictOn' => false, - 'failover' => [], - 'port' => 3306, - 'foreignKeys' => true, - 'busyTimeout' => 1000, - ]; - - public function __construct() - { - parent::__construct(); - - // Ensure that we always set the database group to 'tests' if - // we are currently running an automated test suite, so that - // we don't overwrite live data on accident. - if (ENVIRONMENT === 'testing') { - $this->defaultGroup = 'tests'; - } - } } diff --git a/frameworks/PHP/codeigniter/app/Config/DocTypes.php b/frameworks/PHP/codeigniter/app/Config/DocTypes.php old mode 100755 new mode 100644 index 7e8aaacf09d..788d68fdc11 --- a/frameworks/PHP/codeigniter/app/Config/DocTypes.php +++ b/frameworks/PHP/codeigniter/app/Config/DocTypes.php @@ -2,9 +2,6 @@ namespace Config; -/** - * @immutable - */ class DocTypes { /** diff --git a/frameworks/PHP/codeigniter/app/Config/Email.php b/frameworks/PHP/codeigniter/app/Config/Email.php index 01b805a5c1f..4dce650b32e 100644 --- a/frameworks/PHP/codeigniter/app/Config/Email.php +++ b/frameworks/PHP/codeigniter/app/Config/Email.php @@ -26,7 +26,7 @@ class Email extends BaseConfig public string $mailPath = '/usr/sbin/sendmail'; /** - * SMTP Server Address + * SMTP Server Hostname */ public string $SMTPHost = ''; diff --git a/frameworks/PHP/codeigniter/app/Config/Events.php b/frameworks/PHP/codeigniter/app/Config/Events.php index 993abd24ebc..946285b8951 100644 --- a/frameworks/PHP/codeigniter/app/Config/Events.php +++ b/frameworks/PHP/codeigniter/app/Config/Events.php @@ -23,7 +23,7 @@ * Events::on('create', [$myInstance, 'myMethod']); */ -Events::on('pre_system', static function () { +Events::on('pre_system', static function (): void { if (ENVIRONMENT !== 'testing') { if (ini_get('zlib.output_compression')) { throw FrameworkException::forEnabledZlibOutputCompression(); @@ -44,10 +44,10 @@ */ if (CI_DEBUG && ! is_cli()) { Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'); - Services::toolbar()->respond(); + service('toolbar')->respond(); // Hot Reload route - for framework use on the hot reloader. if (ENVIRONMENT === 'development') { - Services::routes()->get('__hot-reload', static function () { + service('routes')->get('__hot-reload', static function (): void { (new HotReloader())->run(); }); } diff --git a/frameworks/PHP/codeigniter/app/Config/Exceptions.php b/frameworks/PHP/codeigniter/app/Config/Exceptions.php index 4173dcdd1c7..4e3396346b8 100644 --- a/frameworks/PHP/codeigniter/app/Config/Exceptions.php +++ b/frameworks/PHP/codeigniter/app/Config/Exceptions.php @@ -30,6 +30,8 @@ class Exceptions extends BaseConfig * -------------------------------------------------------------------------- * Any status codes here will NOT be logged if logging is turned on. * By default, only 404 (Page Not Found) exceptions are ignored. + * + * @var list */ public array $ignoreCodes = [404]; @@ -51,17 +53,17 @@ class Exceptions extends BaseConfig * Any data that you would like to hide from the debug trace. * In order to specify 2 levels, use "/" to separate. * ex. ['server', 'setup/password', 'secret_token'] + * + * @var list */ public array $sensitiveDataInTrace = []; /** * -------------------------------------------------------------------------- - * LOG DEPRECATIONS INSTEAD OF THROWING? + * WHETHER TO THROW AN EXCEPTION ON DEPRECATED ERRORS * -------------------------------------------------------------------------- - * By default, CodeIgniter converts deprecations into exceptions. Also, - * starting in PHP 8.1 will cause a lot of deprecated usage warnings. - * Use this option to temporarily cease the warnings and instead log those. - * This option also works for user deprecations. + * If set to `true`, DEPRECATED errors are only logged and no exceptions are + * thrown. This option also works for user deprecations. */ public bool $logDeprecations = true; diff --git a/frameworks/PHP/codeigniter/app/Config/Feature.php b/frameworks/PHP/codeigniter/app/Config/Feature.php index 0bc45c6f46c..ec1435af413 100644 --- a/frameworks/PHP/codeigniter/app/Config/Feature.php +++ b/frameworks/PHP/codeigniter/app/Config/Feature.php @@ -10,21 +10,28 @@ class Feature extends BaseConfig { /** - * Enable multiple filters for a route or not. + * Use improved new auto routing instead of the legacy version. + */ + public bool $autoRoutesImproved = true; + + /** + * Use filter execution order in 4.4 or before. + */ + public bool $oldFilterOrder = false; + + /** + * The behavior of `limit(0)` in Query Builder. * - * If you enable this: - * - CodeIgniter\CodeIgniter::handleRequest() uses: - * - CodeIgniter\Filters\Filters::enableFilters(), instead of enableFilter() - * - CodeIgniter\CodeIgniter::tryToRouteIt() uses: - * - CodeIgniter\Router\Router::getFilters(), instead of getFilter() - * - CodeIgniter\Router\Router::handle() uses: - * - property $filtersInfo, instead of $filterInfo - * - CodeIgniter\Router\RouteCollection::getFiltersForRoute(), instead of getFilterForRoute() + * If true, `limit(0)` returns all records. (the behavior of 4.4.x or before in version 4.x.) + * If false, `limit(0)` returns no records. (the behavior of 3.1.9 or later in version 3.x.) */ - public bool $multipleFilters = false; + public bool $limitZeroAsAll = true; /** - * Use improved new auto routing instead of the default legacy version. + * Use strict location negotiation. + * + * By default, the locale is selected based on a loose comparison of the language code (ISO 639-1) + * Enabling strict comparison will also consider the region code (ISO 3166-1 alpha-2). */ - public bool $autoRoutesImproved = false; + public bool $strictLocaleNegotiation = false; } diff --git a/frameworks/PHP/codeigniter/app/Config/Filters.php b/frameworks/PHP/codeigniter/app/Config/Filters.php index 8c02a4acd33..51ae2332027 100644 --- a/frameworks/PHP/codeigniter/app/Config/Filters.php +++ b/frameworks/PHP/codeigniter/app/Config/Filters.php @@ -2,48 +2,51 @@ namespace Config; -use CodeIgniter\Config\BaseConfig; -use CodeIgniter\Filters\CSRF; -use CodeIgniter\Filters\DebugToolbar; -use CodeIgniter\Filters\Honeypot; -use CodeIgniter\Filters\InvalidChars; -use CodeIgniter\Filters\SecureHeaders; +use CodeIgniter\Config\Filters as BaseFilters; -class Filters extends BaseConfig +class Filters extends BaseFilters { /** * Configures aliases for Filter classes to * make reading things nicer and simpler. * - * @var array - * @phpstan-var array + * @var array> + * + * [filter_name => classname] + * or [filter_name => [classname1, classname2, ...]] + */ + public array $aliases = []; + + /** + * List of special required filters. + * + * The filters listed here are special. They are applied before and after + * other kinds of filters, and always applied even if a route does not exist. + * + * Filters set by default provide framework functionality. If removed, + * those functions will no longer work. + * + * @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters + * + * @var array{before: list, after: list} */ - public array $aliases = [ - 'csrf' => CSRF::class, - 'toolbar' => DebugToolbar::class, - 'honeypot' => Honeypot::class, - 'invalidchars' => InvalidChars::class, - 'secureheaders' => SecureHeaders::class, + public array $required = [ + 'before' => [], + 'after' => [], ]; /** * List of filter aliases that are always * applied before and after every request. * - * @var array>>|array> - * @phpstan-var array>|array>> + * @var array{ + * before: array|string}>|list, + * after: array|string}>|list + * } */ public array $globals = [ - 'before' => [ - // 'honeypot', - // 'csrf', - // 'invalidchars', - ], - 'after' => [ - 'toolbar', - // 'honeypot', - // 'secureheaders', - ], + 'before' => [], + 'after' => [], ]; /** @@ -51,11 +54,13 @@ class Filters extends BaseConfig * particular HTTP method (GET, POST, etc.). * * Example: - * 'post' => ['foo', 'bar'] + * 'POST' => ['foo', 'bar'] * * If you use this, you should disable auto-routing because auto-routing * permits any HTTP method to access a controller. Accessing the controller * with a method you don't expect could bypass the filter. + * + * @var array> */ public array $methods = []; @@ -65,6 +70,8 @@ class Filters extends BaseConfig * * Example: * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']] + * + * @var array>> */ public array $filters = []; } diff --git a/frameworks/PHP/codeigniter/app/Config/Format.php b/frameworks/PHP/codeigniter/app/Config/Format.php index 749da3e5fde..0d334d72b3f 100644 --- a/frameworks/PHP/codeigniter/app/Config/Format.php +++ b/frameworks/PHP/codeigniter/app/Config/Format.php @@ -3,7 +3,6 @@ namespace Config; use CodeIgniter\Config\BaseConfig; -use CodeIgniter\Format\FormatterInterface; use CodeIgniter\Format\JSONFormatter; use CodeIgniter\Format\XMLFormatter; @@ -22,7 +21,7 @@ class Format extends BaseConfig * These formats are only checked when the data passed to the respond() * method is an array. * - * @var string[] + * @var list */ public array $supportedResponseFormats = [ 'application/json', @@ -62,16 +61,4 @@ class Format extends BaseConfig 'application/xml' => 0, 'text/xml' => 0, ]; - - /** - * A Factory method to return the appropriate formatter for the given mime type. - * - * @return FormatterInterface - * - * @deprecated This is an alias of `\CodeIgniter\Format\Format::getFormatter`. Use that instead. - */ - public function getFormatter(string $mime) - { - return Services::format()->getFormatter($mime); - } } diff --git a/frameworks/PHP/codeigniter/app/Config/Generators.php b/frameworks/PHP/codeigniter/app/Config/Generators.php index 6566a31e851..cc92c7aa432 100644 --- a/frameworks/PHP/codeigniter/app/Config/Generators.php +++ b/frameworks/PHP/codeigniter/app/Config/Generators.php @@ -23,11 +23,13 @@ class Generators extends BaseConfig * * YOU HAVE BEEN WARNED! * - * @var array + * @var array|string> */ public array $views = [ - 'make:cell' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php', - 'make:cell_view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php', + 'make:cell' => [ + 'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php', + 'view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php', + ], 'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php', 'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php', 'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php', diff --git a/frameworks/PHP/codeigniter/app/Config/Kint.php b/frameworks/PHP/codeigniter/app/Config/Kint.php index cc8b54592b6..931ad47f5fe 100644 --- a/frameworks/PHP/codeigniter/app/Config/Kint.php +++ b/frameworks/PHP/codeigniter/app/Config/Kint.php @@ -2,9 +2,7 @@ namespace Config; -use CodeIgniter\Config\BaseConfig; use Kint\Parser\ConstructablePluginInterface; -use Kint\Renderer\AbstractRenderer; use Kint\Renderer\Rich\TabPluginInterface; use Kint\Renderer\Rich\ValuePluginInterface; @@ -18,7 +16,7 @@ * * @see https://kint-php.github.io/kint/ for details on these settings. */ -class Kint extends BaseConfig +class Kint { /* |-------------------------------------------------------------------------- @@ -27,8 +25,7 @@ class Kint extends BaseConfig */ /** - * @var array - * @phpstan-var list|ConstructablePluginInterface> + * @var list|ConstructablePluginInterface>|null */ public $plugins; @@ -43,17 +40,14 @@ class Kint extends BaseConfig */ public string $richTheme = 'aante-light.css'; public bool $richFolder = false; - public int $richSort = AbstractRenderer::SORT_FULL; /** - * @var array - * @phpstan-var array> + * @var array>|null */ public $richObjectPlugins; /** - * @var array - * @phpstan-var array> + * @var array>|null */ public $richTabPlugins; diff --git a/frameworks/PHP/codeigniter/app/Config/Logger.php b/frameworks/PHP/codeigniter/app/Config/Logger.php index 568c5da658b..799dc2c3908 100644 --- a/frameworks/PHP/codeigniter/app/Config/Logger.php +++ b/frameworks/PHP/codeigniter/app/Config/Logger.php @@ -4,6 +4,7 @@ use CodeIgniter\Config\BaseConfig; use CodeIgniter\Log\Handlers\FileHandler; +use CodeIgniter\Log\Handlers\HandlerInterface; class Logger extends BaseConfig { @@ -36,7 +37,7 @@ class Logger extends BaseConfig * For a live site you'll usually enable Critical or higher (3) to be logged otherwise * your log files will fill up very fast. * - * @var array|int + * @var int|list */ public $threshold = (ENVIRONMENT === 'production') ? 4 : 9; @@ -72,6 +73,8 @@ class Logger extends BaseConfig * * Handlers are executed in the order defined in this array, starting with * the handler on top and continuing down. + * + * @var array, array|string>> */ public array $handlers = [ /* diff --git a/frameworks/PHP/codeigniter/app/Config/Migrations.php b/frameworks/PHP/codeigniter/app/Config/Migrations.php index 3c825667cf6..1dec8b9b3a4 100644 --- a/frameworks/PHP/codeigniter/app/Config/Migrations.php +++ b/frameworks/PHP/codeigniter/app/Config/Migrations.php @@ -25,9 +25,7 @@ class Migrations extends BaseConfig * * This is the name of the table that will store the current migrations state. * When migrations runs it will store in a database table which migration - * level the system is at. It then compares the migration level in this - * table to the $config['migration_version'] if they are not the same it - * will migrate up. This must be set. + * files have already been run. */ public string $table = 'migrations'; diff --git a/frameworks/PHP/codeigniter/app/Config/Mimes.php b/frameworks/PHP/codeigniter/app/Config/Mimes.php index d02df1aba79..c2db7340cd7 100644 --- a/frameworks/PHP/codeigniter/app/Config/Mimes.php +++ b/frameworks/PHP/codeigniter/app/Config/Mimes.php @@ -3,8 +3,6 @@ namespace Config; /** - * Mimes - * * This file contains an array of mime types. It is used by the * Upload class to help identify allowed file types. * @@ -15,13 +13,13 @@ * * When working with mime types, please make sure you have the ´fileinfo´ * extension enabled to reliably detect the media types. - * - * @immutable */ class Mimes { /** * Map of extensions to mime types. + * + * @var array|string> */ public static array $mimes = [ 'hqx' => [ @@ -480,6 +478,8 @@ class Mimes 'application/sla', 'application/vnd.ms-pki.stl', 'application/x-navistyle', + 'model/stl', + 'application/octet-stream', ], ]; diff --git a/frameworks/PHP/codeigniter/app/Config/Modules.php b/frameworks/PHP/codeigniter/app/Config/Modules.php index f84580c856d..53b3edd19cd 100644 --- a/frameworks/PHP/codeigniter/app/Config/Modules.php +++ b/frameworks/PHP/codeigniter/app/Config/Modules.php @@ -9,8 +9,6 @@ * * NOTE: This class is required prior to Autoloader instantiation, * and does not extend BaseConfig. - * - * @immutable */ class Modules extends BaseModules { @@ -25,7 +23,7 @@ class Modules extends BaseModules * * @var bool */ - public $enabled = true; + public $enabled = false; /** * -------------------------------------------------------------------------- @@ -58,7 +56,7 @@ class Modules extends BaseModules * ], * ] * - * @var array + * @var array{only?: list, exclude?: list} */ public $composerPackages = []; @@ -72,7 +70,7 @@ class Modules extends BaseModules * * If it is not listed, only the base application elements will be used. * - * @var string[] + * @var list */ public $aliases = [ 'events', diff --git a/frameworks/PHP/codeigniter/app/Config/Optimize.php b/frameworks/PHP/codeigniter/app/Config/Optimize.php new file mode 100644 index 00000000000..fdba26cd952 --- /dev/null +++ b/frameworks/PHP/codeigniter/app/Config/Optimize.php @@ -0,0 +1,30 @@ + + * @var array */ public $restrictions = [ ROOTPATH => '*', diff --git a/frameworks/PHP/codeigniter/app/Config/Routes.php b/frameworks/PHP/codeigniter/app/Config/Routes.php index d7cfb5a8e97..d1be8eb7909 100644 --- a/frameworks/PHP/codeigniter/app/Config/Routes.php +++ b/frameworks/PHP/codeigniter/app/Config/Routes.php @@ -1,21 +1,20 @@ get('plaintext', static fn () => service('response')->setContentType('text/plain')->setBody('Hello, World!')); +$routes->get('json', static fn () => service('response')->setJSON(['message' => 'Hello, World!'])); -// We get a performance increase by specifying the default -// route since we don't have to scan directories. -//$routes->get('/', 'Home::index'); -$routes->get('plaintext', 'Bench::plaintext'); -$routes->get('json', 'Bench::json'); -$routes->get('fortunes', 'Bench::fortunes'); // /(:num) -$routes->get('db', 'Bench::db'); -$routes->get('queries/(:alphanum)', 'Bench::queries/$1'); -$routes->get('queries/', 'Bench::queries/1'); -$routes->get('update/(:alphanum)', 'Bench::update/$1'); -$routes->get('update/', 'Bench::update/1'); - +$routes->get('db', 'Full::db'); +$routes->get('queries/(:alphanum)', 'Full::queries/$1'); +$routes->get('queries/', 'Full::queries/1'); +$routes->get('update/(:alphanum)', 'Full::update/$1'); +$routes->get('update/', 'Full::update/1'); +$routes->get('fortunes', 'Full::fortunes'); +$routes->get('raw/db', 'Raw::db'); +$routes->get('raw/queries/(:alphanum)', 'Raw::queries/$1'); +$routes->get('raw/queries/', 'Raw::queries/1'); +$routes->get('raw/update/(:alphanum)', 'Raw::update/$1'); +$routes->get('raw/update/', 'Raw::update/1'); +$routes->get('raw/fortunes', 'Raw::fortunes'); diff --git a/frameworks/PHP/codeigniter/app/Config/Routing.php b/frameworks/PHP/codeigniter/app/Config/Routing.php index 8d3c773157c..41a55a73f4e 100644 --- a/frameworks/PHP/codeigniter/app/Config/Routing.php +++ b/frameworks/PHP/codeigniter/app/Config/Routing.php @@ -19,17 +19,21 @@ class Routing extends BaseRouting { /** + * For Defined Routes. * An array of files that contain route definitions. * Route files are read in order, with the first match * found taking precedence. * * Default: APPPATH . 'Config/Routes.php' + * + * @var list */ public array $routeFiles = [ APPPATH . 'Config/Routes.php', ]; /** + * For Defined Routes and Auto Routing. * The default namespace to use for Controllers when no other * namespace has been specified. * @@ -38,23 +42,26 @@ class Routing extends BaseRouting public string $defaultNamespace = 'App\Controllers'; /** + * For Auto Routing. * The default controller to use when no other controller has been * specified. * * Default: 'Home' */ - public string $defaultController = 'Home'; + public string $defaultController = ''; /** + * For Defined Routes and Auto Routing. * The default method to call on the controller when no other * method has been set in the route. * * Default: 'index' */ - public string $defaultMethod = 'index'; + public string $defaultMethod = ''; /** - * Whether to translate dashes in URIs to underscores. + * For Auto Routing. + * Whether to translate dashes in URIs for controller/method to underscores. * Primarily useful when using the auto-routing. * * Default: false @@ -63,13 +70,12 @@ class Routing extends BaseRouting /** * Sets the class/method that should be called if routing doesn't - * find a match. It can be either a closure or the controller/method - * name exactly like a route is defined: Users::index + * find a match. It can be the controller/method name like: Users::index * * This setting is passed to the Router class and handled there. * * If you want to use a closure, you will have to set it in the - * class constructor or the routes file by calling: + * routes file by calling: * * $routes->set404Override(function() { * // Do something here @@ -91,6 +97,7 @@ class Routing extends BaseRouting public bool $autoRoute = false; /** + * For Defined Routes. * If TRUE, will enable the use of the 'prioritize' option * when defining routes. * @@ -99,7 +106,16 @@ class Routing extends BaseRouting public bool $prioritize = false; /** - * Map of URI segments and namespaces. For Auto Routing (Improved). + * For Defined Routes. + * If TRUE, matched multiple URI segments will be passed as one parameter. + * + * Default: false + */ + public bool $multipleSegmentsOneParam = false; + + /** + * For Auto Routing (Improved). + * Map of URI segments and namespaces. * * The key is the first URI segment. The value is the controller namespace. * E.g., @@ -107,7 +123,18 @@ class Routing extends BaseRouting * 'blog' => 'Acme\Blog\Controllers', * ] * - * @var array [ uri_segment => namespace ] + * @var array */ public array $moduleRoutes = []; + + /** + * For Auto Routing (Improved). + * Whether to translate dashes in URIs for controller/method to CamelCase. + * E.g., blog-controller -> BlogController + * + * If you enable this, $translateURIDashes is ignored. + * + * Default: false + */ + public bool $translateUriToCamelCase = true; } diff --git a/frameworks/PHP/codeigniter/app/Config/Security.php b/frameworks/PHP/codeigniter/app/Config/Security.php index 57be4ee4154..635f8b77b9b 100644 --- a/frameworks/PHP/codeigniter/app/Config/Security.php +++ b/frameworks/PHP/codeigniter/app/Config/Security.php @@ -79,23 +79,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Redirect to previous page with error on failure. - */ - public bool $redirect = false; - - /** - * -------------------------------------------------------------------------- - * CSRF SameSite - * -------------------------------------------------------------------------- - * - * Setting for CSRF SameSite cookie token. - * - * Allowed values are: None - Lax - Strict - ''. - * - * Defaults to `Lax` as recommended in this link: - * - * @see https://portswigger.net/web-security/csrf/samesite-cookies * - * @deprecated `Config\Cookie` $samesite property is used. + * @see https://codeigniter4.github.io/userguide/libraries/security.html#redirection-on-failure */ - public string $samesite = 'Lax'; + public bool $redirect = (ENVIRONMENT === 'production'); } diff --git a/frameworks/PHP/codeigniter/app/Config/Session.php b/frameworks/PHP/codeigniter/app/Config/Session.php index ea834805e5a..6944710f705 100644 --- a/frameworks/PHP/codeigniter/app/Config/Session.php +++ b/frameworks/PHP/codeigniter/app/Config/Session.php @@ -19,7 +19,7 @@ class Session extends BaseConfig * - `CodeIgniter\Session\Handlers\MemcachedHandler` * - `CodeIgniter\Session\Handlers\RedisHandler` * - * @phpstan-var class-string + * @var class-string */ public string $driver = FileHandler::class; @@ -99,4 +99,29 @@ class Session extends BaseConfig * DB Group for the database session. */ public ?string $DBGroup = null; + + /** + * -------------------------------------------------------------------------- + * Lock Retry Interval (microseconds) + * -------------------------------------------------------------------------- + * + * This is used for RedisHandler. + * + * Time (microseconds) to wait if lock cannot be acquired. + * The default is 100,000 microseconds (= 0.1 seconds). + */ + public int $lockRetryInterval = 100_000; + + /** + * -------------------------------------------------------------------------- + * Lock Max Retries + * -------------------------------------------------------------------------- + * + * This is used for RedisHandler. + * + * Maximum number of lock acquisition attempts. + * The default is 300 times. That is lock timeout is about 30 (0.1 * 300) + * seconds. + */ + public int $lockMaxRetries = 300; } diff --git a/frameworks/PHP/codeigniter/app/Config/Toolbar.php b/frameworks/PHP/codeigniter/app/Config/Toolbar.php index 97fbda28128..5a3e5045d1e 100644 --- a/frameworks/PHP/codeigniter/app/Config/Toolbar.php +++ b/frameworks/PHP/codeigniter/app/Config/Toolbar.php @@ -31,7 +31,7 @@ class Toolbar extends BaseConfig * List of toolbar collectors that will be called when Debug Toolbar * fires up and collects data from. * - * @var string[] + * @var list */ public array $collectors = [ Timers::class, @@ -49,7 +49,7 @@ class Toolbar extends BaseConfig * Collect Var Data * -------------------------------------------------------------------------- * - * If set to false var data from the views will not be colleted. Useful to + * If set to false var data from the views will not be collected. Useful to * avoid high memory usage when there are lots of data passed to the view. */ public bool $collectVarData = true; @@ -99,6 +99,8 @@ class Toolbar extends BaseConfig * We restrict the values to keep performance as high as possible. * * NOTE: The ROOTPATH will be prepended to all values. + * + * @var list */ public array $watchedDirectories = [ 'app', @@ -111,6 +113,8 @@ class Toolbar extends BaseConfig * * Contains an array of file extensions that will be watched for changes and * used to determine if the hot-reload feature should reload the page or not. + * + * @var list */ public array $watchedExtensions = [ 'php', 'css', 'js', 'html', 'svg', 'json', 'env', diff --git a/frameworks/PHP/codeigniter/app/Config/Validation.php b/frameworks/PHP/codeigniter/app/Config/Validation.php index 017dac5a584..6342dbbe7d3 100644 --- a/frameworks/PHP/codeigniter/app/Config/Validation.php +++ b/frameworks/PHP/codeigniter/app/Config/Validation.php @@ -18,7 +18,7 @@ class Validation extends BaseConfig * Stores the classes that contain the * rules that are available. * - * @var string[] + * @var list */ public array $ruleSets = [ Rules::class, diff --git a/frameworks/PHP/codeigniter/app/Config/View.php b/frameworks/PHP/codeigniter/app/Config/View.php index 78cd547e3b8..cf8dd06f106 100644 --- a/frameworks/PHP/codeigniter/app/Config/View.php +++ b/frameworks/PHP/codeigniter/app/Config/View.php @@ -5,6 +5,10 @@ use CodeIgniter\Config\View as BaseView; use CodeIgniter\View\ViewDecoratorInterface; +/** + * @phpstan-type parser_callable (callable(mixed): mixed) + * @phpstan-type parser_callable_string (callable(mixed): mixed)&string + */ class View extends BaseView { /** @@ -30,7 +34,8 @@ class View extends BaseView * { title|esc(js) } * { created_on|date(Y-m-d)|esc(attr) } * - * @var array + * @var array + * @phpstan-var array */ public $filters = []; @@ -39,7 +44,8 @@ class View extends BaseView * by the core Parser by creating aliases that will be replaced with * any callable. Can be single or tag pair. * - * @var array + * @var array|string> + * @phpstan-var array|parser_callable_string|parser_callable> */ public $plugins = []; @@ -50,7 +56,7 @@ class View extends BaseView * * All classes must implement CodeIgniter\View\ViewDecoratorInterface * - * @var class-string[] + * @var list> */ public array $decorators = []; } diff --git a/frameworks/PHP/codeigniter/app/Controllers/BaseController.php b/frameworks/PHP/codeigniter/app/Controllers/BaseController.php deleted file mode 100644 index fb44007e5c7..00000000000 --- a/frameworks/PHP/codeigniter/app/Controllers/BaseController.php +++ /dev/null @@ -1,58 +0,0 @@ -session = \Config\Services::session(); - } -} diff --git a/frameworks/PHP/codeigniter/app/Controllers/Bench.php b/frameworks/PHP/codeigniter/app/Controllers/Bench.php deleted file mode 100644 index fd3451938b2..00000000000 --- a/frameworks/PHP/codeigniter/app/Controllers/Bench.php +++ /dev/null @@ -1,80 +0,0 @@ -response->setContentType('text/plain'); - return $this->response->setBody('Hello, World!'); - } - - public function json() - { - return $this->response->setJSON(['message' => 'Hello, World!']); - } - - public function db() - { - $worlds = Dbraw::get() - ->query('SELECT * FROM World WHERE id = ?', array(mt_rand(1, 10000))) - ->getRow(); - - return $this->response->setJSON($worlds); - } - - public function queries($queries = 1) - { - $worlds = []; - $queries = is_numeric($queries) ? min(max($queries, 1), 500) : 1; - - for ($i = 0; $i < $queries; ++$i) { - $worlds[] = Dbraw::get() - ->query('SELECT * FROM World WHERE id = ?', array(mt_rand(1, 10000))) - ->getRow(); - } - - return $this->response->setJSON($worlds); - } - - public function update($queries = 1) - { - $worlds = []; - $queries = is_numeric($queries) ? min(max($queries, 1), 500) : 1; - - for ($i = 0; $i < $queries; ++$i) { - $id = mt_rand(1, 10000); - $world = Dbraw::get() - ->query('SELECT * FROM World WHERE id = ?', [$id]) - ->getRow(); - - $world->randomNumber = mt_rand(1, 10000); - Dbraw::get() - ->query('UPDATE World SET randomNumber=? WHERE id=?', [$world->randomNumber, $id]); - $worlds[] = $world; - } - - return $this->response->setJSON($worlds); - } - - public function fortunes() - { - $fortunes = Dbraw::get() - ->query('SELECT * FROM Fortune') - ->getResultArray(); - - $fortunes[] = [ - 'id' => 0, - 'message' => 'Additional fortune added at request time.' - ]; - - usort($fortunes, fn($a, $b) => $a['message'] <=> $b['message']); - - $data['fortunes'] = $fortunes; - - return view('fortunes', $data); - } -} diff --git a/frameworks/PHP/codeigniter/app/Controllers/Full.php b/frameworks/PHP/codeigniter/app/Controllers/Full.php new file mode 100644 index 00000000000..d0fd6612bf2 --- /dev/null +++ b/frameworks/PHP/codeigniter/app/Controllers/Full.php @@ -0,0 +1,54 @@ +response->setJSON(model('World')->find(mt_rand(1, 10000))); + } + + public function queries($queries = 1) + { + $queries = is_numeric($queries) ? min(max($queries, 1), 500) : 1; + $world = []; + + while ($queries--) { + $world[] = model('World')->find(mt_rand(1, 10000)); + } + + return $this->response->setJSON($world); + } + + public function update($queries = 1) + { + $queries = is_numeric($queries) ? min(max($queries, 1), 500) : 1; + $world = []; + + while ($queries--) { + $row = model('World')->find(mt_rand(1, 10000)); + $row['randomNumber'] = mt_rand(1, 10000); + $world[] = $row; + model('World')->save($row); + } + + return $this->response->setJSON($world); + } + + public function fortunes() + { + $fortunes = array_column(model('Fortune')->findAll(), 'message', 'id'); + $fortunes[0] = 'Additional fortune added at request time.'; + asort($fortunes); + + return service('renderer')->setVar('fortunes', $fortunes)->render('fortunes'); + } +} diff --git a/frameworks/PHP/codeigniter/app/Controllers/Home.php b/frameworks/PHP/codeigniter/app/Controllers/Home.php deleted file mode 100644 index 59343333099..00000000000 --- a/frameworks/PHP/codeigniter/app/Controllers/Home.php +++ /dev/null @@ -1,11 +0,0 @@ -response->setJSON(db_connect()->query('SELECT id, randomNumber FROM World WHERE id = ?', mt_rand(1, 10000))->getRowArray()); + } + + public function queries($queries = 1) + { + $db = db_connect(); + + $select = $db->prepare(static fn ($db) => $db->query('SELECT id, randomNumber FROM World WHERE id = ?')); + + $queries = is_numeric($queries) ? min(max($queries, 1), 500) : 1; + $world = []; + + while ($queries--) { + $world[] = $select->execute(mt_rand(1, 10000))->getRowArray(); + } + + return $this->response->setJSON($world); + } + + public function update($queries = 1) + { + $db = db_connect(); + + $select = $db->prepare(static fn ($db) => $db->query('SELECT id, randomNumber FROM World WHERE id = ?')); + + $update = $db->prepare(static fn ($db) => $db->query('UPDATE World SET randomNumber = ? WHERE id = ?')); + + $queries = is_numeric($queries) ? min(max($queries, 1), 500) : 1; + $world = []; + + while ($queries--) { + $row = $select->execute(mt_rand(1, 10000))->getRowArray(); + $row['randomNumber'] = mt_rand(1, 10000); + $update->execute($row['randomNumber'], $row['id']); + $world[] = $row; + } + + return $this->response->setJSON($world); + } + + public function fortunes() + { + $fortunes = array_column( + db_connect()->query('SELECT id, message FROM Fortune')->getResultArray(), 'message', 'id' + ); + $fortunes[0] = 'Additional fortune added at request time.'; + asort($fortunes); + + return service('renderer')->setVar('fortunes', $fortunes)->render('fortunes'); + } +} diff --git a/frameworks/PHP/codeigniter/app/Database/Migrations/.gitkeep b/frameworks/PHP/codeigniter/app/Database/Migrations/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/codeigniter/app/Database/Seeds/.gitkeep b/frameworks/PHP/codeigniter/app/Database/Seeds/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/codeigniter/app/Filters/.gitkeep b/frameworks/PHP/codeigniter/app/Filters/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/codeigniter/app/Helpers/.gitkeep b/frameworks/PHP/codeigniter/app/Helpers/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/codeigniter/app/Language/.gitkeep b/frameworks/PHP/codeigniter/app/Language/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/codeigniter/app/Language/en/Validation.php b/frameworks/PHP/codeigniter/app/Language/en/Validation.php deleted file mode 100644 index 54d1e7a4a27..00000000000 --- a/frameworks/PHP/codeigniter/app/Language/en/Validation.php +++ /dev/null @@ -1,4 +0,0 @@ - 'int', + 'randomNumber' => 'int', + ]; + protected $allowedFields = ['randomNumber']; +} diff --git a/frameworks/PHP/codeigniter/app/Models/WorldsModel.php b/frameworks/PHP/codeigniter/app/Models/WorldsModel.php deleted file mode 100644 index 133992eb998..00000000000 --- a/frameworks/PHP/codeigniter/app/Models/WorldsModel.php +++ /dev/null @@ -1,10 +0,0 @@ -getFile()) . ':' . $exception->getLine(), 'green')); -CLI::newLine(); - -// The backtrace -if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) { - $backtraces = $exception->getTrace(); - - if ($backtraces) { - CLI::write('Backtrace:', 'green'); - } - - foreach ($backtraces as $i => $error) { - $padFile = ' '; // 4 spaces - $padClass = ' '; // 7 spaces - $c = str_pad($i + 1, 3, ' ', STR_PAD_LEFT); - - if (isset($error['file'])) { - $filepath = clean_path($error['file']) . ':' . $error['line']; - - CLI::write($c . $padFile . CLI::color($filepath, 'yellow')); - } else { - CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow')); - } - - $function = ''; - - if (isset($error['class'])) { - $type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type']; - $function .= $padClass . $error['class'] . $type . $error['function']; - } elseif (! isset($error['class']) && isset($error['function'])) { - $function .= $padClass . $error['function']; - } - - $args = implode(', ', array_map(static function ($value) { - switch (true) { - case is_object($value): - return 'Object(' . get_class($value) . ')'; - - case is_array($value): - return count($value) ? '[...]' : '[]'; - - case $value === null: - return 'null'; // return the lowercased version - - default: - return var_export($value, true); - } - }, array_values($error['args'] ?? []))); - - $function .= '(' . $args . ')'; - - CLI::write($function); - CLI::newLine(); - } -} diff --git a/frameworks/PHP/codeigniter/app/Views/errors/cli/production.php b/frameworks/PHP/codeigniter/app/Views/errors/cli/production.php deleted file mode 100644 index 7db744ecea9..00000000000 --- a/frameworks/PHP/codeigniter/app/Views/errors/cli/production.php +++ /dev/null @@ -1,5 +0,0 @@ - + + + + <?= lang('Errors.badRequest') ?> + + + + +
+

400

+ +

+ + + + + +

+
+ + diff --git a/frameworks/PHP/codeigniter/app/Views/errors/html/error_404.php b/frameworks/PHP/codeigniter/app/Views/errors/html/error_404.php index c3010132f9b..e506f08350e 100644 --- a/frameworks/PHP/codeigniter/app/Views/errors/html/error_404.php +++ b/frameworks/PHP/codeigniter/app/Views/errors/html/error_404.php @@ -77,7 +77,7 @@ - +

diff --git a/frameworks/PHP/codeigniter/app/Views/errors/html/error_exception.php b/frameworks/PHP/codeigniter/app/Views/errors/html/error_exception.php deleted file mode 100644 index f311d910c0f..00000000000 --- a/frameworks/PHP/codeigniter/app/Views/errors/html/error_exception.php +++ /dev/null @@ -1,392 +0,0 @@ - - - - - - - - <?= esc($title) ?> - - - - - - - -
-
-

getCode() ? ' #' . $exception->getCode() : '') ?>

-

- getMessage())) ?> - getMessage())) ?>" - rel="noreferrer" target="_blank">search → -

-
-
- - -
-

at line

- - -
- -
- -
- -
- - - -
- - -
- -
    - $row) : ?> - -
  1. -

    - - - - - {PHP internal code} - - - - -   —   - - - ( arguments ) -

    - - - getParameters(); - } - - foreach ($row['args'] as $key => $value) : ?> - - - - - - -
    name : "#{$key}") ?>
    -
    - - () - - - - -   —   () - -

    - - - -
    - -
    - -
  2. - - -
- -
- - -
- - - -

$

- - - - - - - - - - $value) : ?> - - - - - - -
KeyValue
- - - -
- -
- - - - - - -

Constants

- - - - - - - - - - $value) : ?> - - - - - - -
KeyValue
- - - -
- -
- -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PathgetUri()) ?>
HTTP MethodgetMethod())) ?>
IP AddressgetIPAddress()) ?>
Is AJAX Request?isAJAX() ? 'yes' : 'no' ?>
Is CLI Request?isCLI() ? 'yes' : 'no' ?>
Is Secure Request?isSecure() ? 'yes' : 'no' ?>
User AgentgetUserAgent()->getAgentString()) ?>
- - - - - - - - -

$

- - - - - - - - - - $value) : ?> - - - - - - -
KeyValue
- - - -
- -
- - - - - -
- No $_GET, $_POST, or $_COOKIE Information to show. -
- - - - headers(); ?> - - -

Headers

- - - - - - - - - - - - - - - - -
HeaderValue
getName(), 'html') ?>getValueLine(), 'html') ?>
- - -
- - - setStatusCode(http_response_code()); - ?> -
- - - - - -
Response StatusgetStatusCode() . ' - ' . $response->getReasonPhrase()) ?>
- - headers(); ?> - - - -

Headers

- - - - - - - - - - - - - - - - -
HeaderValue
getHeaderLine($name), 'html') ?>
- - -
- - -
- - -
    - -
  1. - -
-
- - -
- - - - - - - - - - - - - - - - -
Memory Usage
Peak Memory Usage:
Memory Limit:
- -
- -
- -
- - - - - diff --git a/frameworks/PHP/codeigniter/app/Views/fortunes.php b/frameworks/PHP/codeigniter/app/Views/fortunes.php index 3c473d15564..8103b68e8dc 100644 --- a/frameworks/PHP/codeigniter/app/Views/fortunes.php +++ b/frameworks/PHP/codeigniter/app/Views/fortunes.php @@ -1,9 +1,13 @@ -Fortunes - - - - - - - -
idmessage
\ No newline at end of file + + + + Fortunes + + + + $message): ?> + + +
idmessage
+ + \ No newline at end of file diff --git a/frameworks/PHP/codeigniter/app/Views/welcome_message.php b/frameworks/PHP/codeigniter/app/Views/welcome_message.php deleted file mode 100644 index 6d5da23f122..00000000000 --- a/frameworks/PHP/codeigniter/app/Views/welcome_message.php +++ /dev/null @@ -1,325 +0,0 @@ - - - - - Welcome to CodeIgniter 4! - - - - - - - - - - - -
- - - -
- -

Welcome to CodeIgniter

- -

The small framework with powerful features

- -
- -
- - - -
- -

About this page

- -

The page you are looking at is being generated dynamically by CodeIgniter.

- -

If you would like to edit this page you will find it located at:

- -
app/Views/welcome_message.php
- -

The corresponding controller for this page can be found at:

- -
app/Controllers/Home.php
- -
- -
- -
- -

Go further

- -

- - Learn -

- -

The User Guide contains an introduction, tutorial, a number of "how to" - guides, and then reference documentation for the components that make up - the framework. Check the User Guide !

- -

- - Discuss -

- -

CodeIgniter is a community-developed open source project, with several - venues for the community members to gather and exchange ideas. View all - the threads on CodeIgniter's forum, or chat on Slack !

- -

- - Contribute -

- -

CodeIgniter is a community driven project and accepts contributions - of code and documentation from the community. Why not - - join us ?

- -
- -
- - - -
-
- -

Page rendered in {elapsed_time} seconds

- -

Environment:

- -
- -
- -

© CodeIgniter Foundation. CodeIgniter is open source project released under the MIT - open source licence.

- -
- -
- - - - - - - - - diff --git a/frameworks/PHP/codeigniter/benchmark_config.json b/frameworks/PHP/codeigniter/benchmark_config.json index 31a47411198..3f0a2975edf 100644 --- a/frameworks/PHP/codeigniter/benchmark_config.json +++ b/frameworks/PHP/codeigniter/benchmark_config.json @@ -15,7 +15,7 @@ "framework": "codeigniter", "language": "PHP", "flavor": "PHP8.1", - "orm": "Raw", + "orm": "Full", "platform": "FPM/FastCGI", "webserver": "nginx", "os": "Linux", @@ -23,6 +23,27 @@ "display_name": "codeigniter4", "notes": "", "versus": "php" + }, + "raw": { + "db_url": "/raw/db", + "query_url": "/raw/queries/", + "update_url": "/raw/update/", + "fortune_url": "/raw/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "codeigniter", + "language": "PHP", + "flavor": "PHP8.1", + "orm": "Raw", + "platform": "FPM/FastCGI", + "webserver": "nginx", + "os": "Linux", + "database_os": "Linux", + "display_name": "codeigniter4-raw", + "notes": "", + "versus": "php" } }] } diff --git a/frameworks/PHP/codeigniter/codeigniter-raw.dockerfile b/frameworks/PHP/codeigniter/codeigniter-raw.dockerfile new file mode 100644 index 00000000000..0737e1eeed9 --- /dev/null +++ b/frameworks/PHP/codeigniter/codeigniter-raw.dockerfile @@ -0,0 +1,29 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ + apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null + +RUN apt-get update > /dev/null && apt-get install -yqq nginx git unzip \ + php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-intl php8.5-curl > /dev/null + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +COPY deploy/conf/* /etc/php/8.5/fpm/ + +ADD ./ /codeigniter +WORKDIR /codeigniter + +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev +#--quiet + +RUN chmod -R 777 writable + +EXPOSE 8080 + +CMD service php8.5-fpm start && \ + nginx -c /codeigniter/deploy/nginx.conf diff --git a/frameworks/PHP/codeigniter/config.toml b/frameworks/PHP/codeigniter/config.toml index a5a4eac2bbb..8e5e15b1f33 100644 --- a/frameworks/PHP/codeigniter/config.toml +++ b/frameworks/PHP/codeigniter/config.toml @@ -1,12 +1,30 @@ [framework] -name = "codeigniter" +name = "CodeIgniter" +authors = ["CodeIgniter Foundation "] +github = "https://github.com/codeigniter4/CodeIgniter4" [main] -urls.plaintext = "/index.php/bench/plaintext" -urls.json = "/index.php/bench/json" -urls.db = "/index.php/bench/db" -urls.query = "/index.php/bench/dbquery/" -urls.fortune = "/index.php/bench/fortunes" +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/update/" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Fullstack" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Full" +platform = "FPM/FastCGI" +webserver = "nginx" +versus = "php" + +[raw] +urls.db = "/raw/db" +urls.query = "/raw/queries/" +urls.update = "/raw/update/" +urls.fortune = "/raw/fortunes" approach = "Realistic" classification = "Fullstack" database = "MySQL" diff --git a/frameworks/PHP/codeigniter/deploy/conf/php.ini b/frameworks/PHP/codeigniter/deploy/conf/php.ini index 82133535145..45a6094f45b 100644 --- a/frameworks/PHP/codeigniter/deploy/conf/php.ini +++ b/frameworks/PHP/codeigniter/deploy/conf/php.ini @@ -1911,6 +1911,8 @@ opcache.huge_code_pages=1 opcache.jit_buffer_size = 128M opcache.jit = tracing +opcache.preload=/codeigniter/preload.php +opcache.preload_user=www-data ; Local Variables: ; tab-width: 4 diff --git a/frameworks/PHP/codeigniter/preload.php b/frameworks/PHP/codeigniter/preload.php new file mode 100644 index 00000000000..288b30b4ef4 --- /dev/null +++ b/frameworks/PHP/codeigniter/preload.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use CodeIgniter\Boot; +use Config\Paths; + +/* + *--------------------------------------------------------------- + * Sample file for Preloading + *--------------------------------------------------------------- + * See https://www.php.net/manual/en/opcache.preloading.php + * + * How to Use: + * 0. Copy this file to your project root folder. + * 1. Set the $paths property of the preload class below. + * 2. Set opcache.preload in php.ini. + * php.ini: + * opcache.preload=/path/to/preload.php + */ + +// Load the paths config file +require __DIR__ . '/app/Config/Paths.php'; + +// Path to the front controller +define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); + +class preload +{ + /** + * @var array Paths to preload. + */ + private array $paths = [ + [ + 'include' => __DIR__ . '/vendor/codeigniter4/framework/system', // Change this path if using manual installation + 'exclude' => [ + // Not needed if you don't use them. + '/system/Database/OCI8/', + '/system/Database/Postgre/', + '/system/Database/SQLite3/', + '/system/Database/SQLSRV/', + // Not needed for web apps. + '/system/Database/Seeder.php', + '/system/Test/', + '/system/CLI/', + '/system/Commands/', + '/system/Publisher/', + '/system/ComposerScripts.php', + // Not Class/Function files. + '/system/Config/Routes.php', + '/system/Language/', + '/system/bootstrap.php', + '/system/util_bootstrap.php', + '/system/rewrite.php', + '/Views/', + // Errors occur. + '/system/ThirdParty/', + ], + ], + ]; + + public function __construct() + { + $this->loadAutoloader(); + } + + private function loadAutoloader(): void + { + $paths = new Paths(); + require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php'; + + Boot::preload($paths); + } + + /** + * Load PHP files. + */ + public function load(): void + { + foreach ($this->paths as $path) { + $directory = new RecursiveDirectoryIterator($path['include']); + $fullTree = new RecursiveIteratorIterator($directory); + $phpFiles = new RegexIterator( + $fullTree, + '/.+((? $file) { + foreach ($path['exclude'] as $exclude) { + if (str_contains($file[0], $exclude)) { + continue 2; + } + } + + require_once $file[0]; + // Uncomment only for debugging (to inspect which files are included). + // Never use this in production - preload scripts must not generate output. + // echo 'Loaded: ' . $file[0] . "\n"; + } + } + } +} + +(new preload())->load(); diff --git a/frameworks/PHP/codeigniter/public/index.php b/frameworks/PHP/codeigniter/public/index.php index df2853effed..96b04a3c09b 100644 --- a/frameworks/PHP/codeigniter/public/index.php +++ b/frameworks/PHP/codeigniter/public/index.php @@ -23,8 +23,6 @@ */ const ENVIRONMENT = "production"; -const CI_DEBUG = false; - // Load our paths config file // This is the line that might need to be changed, depending on your folder structure. diff --git a/frameworks/PHP/fomo/.env b/frameworks/PHP/fomo/.env deleted file mode 100644 index 9e3a7f21887..00000000000 --- a/frameworks/PHP/fomo/.env +++ /dev/null @@ -1,21 +0,0 @@ -APP_NAME=Fomo -APP_TIMEZONE=UTC -APP_ENV=local -APP_SSL=false -APP_DEBUG=false -APP_URL=http://localhost - -DB_HOST=tfb-database -DB_PORT=3306 -DB_DATABASE=hello_world -DB_USERNAME=benchmarkdbuser -DB_PASSWORD=benchmarkdbpass -DB_CHARSET=utf8mb4 -DB_COLLATION=utf8mb4_unicode_ci - -REDIS_HOST=127.0.0.1 -REDIS_PASSWORD=null -REDIS_USERNAME=null -REDIS_PORT=6379 -REDIS_DATABASE=0 - diff --git a/frameworks/PHP/fomo/.gitignore b/frameworks/PHP/fomo/.gitignore deleted file mode 100644 index a757318145d..00000000000 --- a/frameworks/PHP/fomo/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -.buildpath -.settings/ -.project -*.patch -.idea/ -.git/ -runtime/ -vendor/ -.phpintel/ -.DS_Store -*.lock -.phpunit* \ No newline at end of file diff --git a/frameworks/PHP/fomo/README.md b/frameworks/PHP/fomo/README.md deleted file mode 100644 index 31c6ddcbed1..00000000000 --- a/frameworks/PHP/fomo/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Introduction - -Fomo is a web application framework based. - -We tried to implement Fomo in the simplest possible way so that anyone can use it. - -Fomo supports the following: - -- Simple, fast routing engine. -- Processing work in the background. -- Queued job processing. -- And more... - -Fomo is very fast, simple and for use in large scale projects. - -# Original intention - -Here's 3 reason why you should use Fomo: - -- Fomo is very simple (less to learn and train others on). -- Fomo is very fast (uses fewer resources to do the same thing). -- Fomo is another tool that developers can use to solve their complex problems in a simple way. - -# Documentation - -[https://fomo-framework.github.io/docs/](https://fomo-framework.github.io/docs/) diff --git a/frameworks/PHP/fomo/app/Exceptions/Handler.php b/frameworks/PHP/fomo/app/Exceptions/Handler.php deleted file mode 100644 index a4cff760343..00000000000 --- a/frameworks/PHP/fomo/app/Exceptions/Handler.php +++ /dev/null @@ -1,30 +0,0 @@ -json([ - 'message' => 'not found' - ] , 404); - } - - public function notAllowedHttpException(Request $request): string - { - return response()->json([ - 'message' => "this is route supported {$request->method()} method" - ] , 405); - } - - public function InternalErrorException(Request $request, Throwable $error): string - { - return response()->json([ - 'message' => 'internal error' - ] , 500); - } -} diff --git a/frameworks/PHP/fomo/benchmark_config.json b/frameworks/PHP/fomo/benchmark_config.json deleted file mode 100755 index 817107d03d2..00000000000 --- a/frameworks/PHP/fomo/benchmark_config.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "framework": "fomo", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/query?queries=", - "update_url": "/update?queries=", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "database": "mysql", - "framework": "Fomo", - "language": "PHP", - "flavor": "None", - "orm": "Full", - "platform": "swoole", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Fomo", - "notes": "", - "tags": ["broken"], - "versus": "swoole" - } - } - ] - } diff --git a/frameworks/PHP/fomo/composer.json b/frameworks/PHP/fomo/composer.json deleted file mode 100644 index ea983317469..00000000000 --- a/frameworks/PHP/fomo/composer.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "fomo/fomo", - "description": "The Fomo Framework", - "keywords": ["framework", "fomo" , "high performance"], - "type": "project", - "license": "MIT", - "authors": [ - { - "name": "Amir", - "email": "faramarzii.amir@gmail.com" - } - ], - "require": { - "php" : ">=8.1", - "fomo/framework": "^2.0" - }, - "autoload": { - "psr-4": { - "App\\" : "app/" , - "Database\\" : "database/", - "Storage\\Routes\\" : "storage/routes/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "scripts": { - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ] - }, - "minimum-stability": "dev", - "prefer-stable": true, - "require-dev": { - "fakerphp/faker": "^1.15", - "phpunit/phpunit": "^9.5" - }, - "config": { - "allow-plugins": { - "php-http/discovery": true - } - } -} diff --git a/frameworks/PHP/fomo/config.toml b/frameworks/PHP/fomo/config.toml deleted file mode 100644 index 1067719fe39..00000000000 --- a/frameworks/PHP/fomo/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "fomo" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.update = "/updates/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "swoole" -webserver = "None" -versus = "swoole" \ No newline at end of file diff --git a/frameworks/PHP/fomo/config/app.php b/frameworks/PHP/fomo/config/app.php deleted file mode 100644 index 0f6c003a1a6..00000000000 --- a/frameworks/PHP/fomo/config/app.php +++ /dev/null @@ -1,8 +0,0 @@ - env('APP_NAME' , 'Fomo'), - 'timezone' => env('APP_TIMEZONE' , 'UTC'), - 'faker_locale' => 'en_US' , - 'locale' => 'en' , -]; \ No newline at end of file diff --git a/frameworks/PHP/fomo/config/database.php b/frameworks/PHP/fomo/config/database.php deleted file mode 100644 index 004a473cc99..00000000000 --- a/frameworks/PHP/fomo/config/database.php +++ /dev/null @@ -1,67 +0,0 @@ - env('DB_CONNECTION', 'mysql'), - - 'connections' => [ - - 'sqlite' => [ - 'driver' => 'sqlite', - 'url' => env('DATABASE_URL'), - 'database' => env('DB_DATABASE', databasePath('database.sqlite')), - 'prefix' => '', - 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), - ], - - 'mysql' => [ - 'driver' => 'mysql', - 'url' => env('DATABASE_URL'), - 'host' => env('DB_HOST', '127.0.0.1'), - 'port' => env('DB_PORT', '3306'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'unix_socket' => env('DB_SOCKET', ''), - 'charset' => 'utf8mb4', - 'collation' => 'utf8mb4_unicode_ci', - 'prefix' => '', - 'prefix_indexes' => true, - 'strict' => true, - 'engine' => null, - 'options' => extension_loaded('pdo_mysql') ? array_filter([ - PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), - ]) : [], - ], - - 'pgsql' => [ - 'driver' => 'pgsql', - 'url' => env('DATABASE_URL'), - 'host' => env('DB_HOST', '127.0.0.1'), - 'port' => env('DB_PORT', '5432'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - 'prefix_indexes' => true, - 'search_path' => 'public', - 'sslmode' => 'prefer', - ], - - 'sqlsrv' => [ - 'driver' => 'sqlsrv', - 'url' => env('DATABASE_URL'), - 'host' => env('DB_HOST', 'localhost'), - 'port' => env('DB_PORT', '1433'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - 'prefix_indexes' => true, - // 'encrypt' => env('DB_ENCRYPT', 'yes'), - // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), - ], - - ] -]; \ No newline at end of file diff --git a/frameworks/PHP/fomo/config/server.php b/frameworks/PHP/fomo/config/server.php deleted file mode 100755 index 273b2cf3d4a..00000000000 --- a/frameworks/PHP/fomo/config/server.php +++ /dev/null @@ -1,82 +0,0 @@ - SWOOLE_BASE , - 'host' => '0.0.0.0', - 'port' => 9000 , - 'sockType' => SWOOLE_SOCK_TCP , - 'additional' => [ - 'worker_num' => env('APP_WORKER_COUNT' , cpuCount() * 2) , - /* - * log level - * SWOOLE_LOG_DEBUG (default) - * SWOOLE_LOG_TRACE - * SWOOLE_LOG_INFO - * SWOOLE_LOG_NOTICE - * SWOOLE_LOG_WARNING - * SWOOLE_LOG_ERROR - */ - 'log_level' => SWOOLE_LOG_DEBUG , - 'log_file' => storagePath('logs/fomo.log') , - - /* - This key causes Fomo to receive a complete HTTP data packet and prevents it from receiving incomplete HTTP packets. - */ - 'open_http_protocol' => true, - ], - - 'ssl' => [ - 'ssl_cert_file' => null , - 'ssl_key_file' => null , - ] , - - /* - * The following services are created for better performance in the program, only one object is created from them and they can be used throughout the program - */ - 'services' => [ - Fomo\Services\Cache::class , - Fomo\Services\Database::class , - Fomo\Services\Language::class , - Fomo\Services\Response::class , - Fomo\Services\Validation::class , - ] , - - /* - * Files and folders that must be changed in real time - */ - 'watcher' => [ - 'app', - 'config', - 'database', - 'language', - 'routes', - 'composer.lock', - '.env', - ] , - - /* - * Each of the following causes changes to the performance of the desired class. (so be careful in using them) - */ - 'advanceMode' => [ - /* - * advanced mode in Fomo\Request\Request class - * - * By activating the advanced mode in this class, you can access the data you want in an advanced way - * For example, consider that the user has sent you a array of the information of several customers. - * If the advanced mode is not active, you can only access an array of all customer information - * - * For example, the: - * $request->get('customers') - * - * But if the advanced mode is active, you can access any data you need from customers - * For example, the: - * $request->get('customers.*.name') - */ - 'request' => DISABLE - ] -]; diff --git a/frameworks/PHP/fomo/deploy/php-async.ini b/frameworks/PHP/fomo/deploy/php-async.ini deleted file mode 100644 index 6c94704a357..00000000000 --- a/frameworks/PHP/fomo/deploy/php-async.ini +++ /dev/null @@ -1,13 +0,0 @@ -opcache.enable=1 -opcache.enable_cli=1 -opcache.validate_timestamps=0 -opcache.save_comments=0 -opcache.enable_file_override=1 -opcache.memory_consumption=256 -opcache.interned_strings_buffer=16 -opcache.max_accelerated_files=7963 -opcache.preload_user=www-data - -mysqlnd.collect_statistics = Off - -memory_limit = 512M diff --git a/frameworks/PHP/fomo/engineer b/frameworks/PHP/fomo/engineer deleted file mode 100644 index d5794972427..00000000000 --- a/frameworks/PHP/fomo/engineer +++ /dev/null @@ -1,98 +0,0 @@ -load(); - -/* - * set timezone - */ -date_default_timezone_set(config('app.timezone')); - -/* - * create console - */ -$application = new Application(); - -/* - * server commands - */ -$application->add(new StartServerCommand()); -$application->add(new ReloadServerCommand()); -$application->add(new StatusServerCommand()); -$application->add(new StopServerCommand()); - -/* - * build commands - */ -$application->add(new BuildControllerCommand()); -$application->add(new BuildExceptionCommand()); -$application->add(new BuildMiddlewareCommand()); -$application->add(new BuildResourceCommand()); -$application->add(new BuildTestCommand()); -$application->add(new BuildJobCommand()); -$application->add(new BuildTaskCommand()); -$application->add(new BuildServiceCommand()); - -/* - * tests commands - */ -$application->add(new TestsRunCommand()); - -/* - * factory commands - */ -$application->add(new FactoryStartCommand()); - -/* - * queue commands - */ -$application->add(new QueueStartCommand()); -$application->add(new QueueStatusCommand()); -$application->add(new QueueStopCommand()); - -/* - * scheduler commands - */ -$application->add(new SchedulerStartCommand()); -$application->add(new SchedulerStatusCommand()); -$application->add(new SchedulerStopCommand()); - -/* - * run console - */ -$application->run(); diff --git a/frameworks/PHP/fomo/fomo.dockerfile b/frameworks/PHP/fomo/fomo.dockerfile deleted file mode 100644 index eee3c65e802..00000000000 --- a/frameworks/PHP/fomo/fomo.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM phpswoole/swoole:5.1.3-php8.3 - -RUN docker-php-ext-install pcntl opcache > /dev/null - -# RUN pecl install --force redis - -COPY deploy/php-async.ini /usr/local/etc/php/php.ini - -COPY . /fomo - -WORKDIR /fomo - -RUN composer install --no-dev --quiet -RUN composer dump-autoload --optimize --quiet - -RUN chmod -R 777 /fomo/storage - -# USER www-data - -EXPOSE 9000 - -ENTRYPOINT [ "php", "engineer", "server:start" ] diff --git a/frameworks/PHP/fomo/language/validation/en/errors.php b/frameworks/PHP/fomo/language/validation/en/errors.php deleted file mode 100644 index b0d0c5bd160..00000000000 --- a/frameworks/PHP/fomo/language/validation/en/errors.php +++ /dev/null @@ -1,30 +0,0 @@ - [ - 'required' => 'The :attribute is mandatory' , - 'string' => 'The :attribute must be a string' , - 'integer' => 'The :attribute must be a number' , - 'boolean' => 'The :attribute must be true or false' , - 'array' => 'The :attribute must be an array' , - 'email' => 'The :attribute must be the email address' , - 'regex' => 'The template :attribute is wrong' , - 'notRegex' => 'The template :attribute is wrong' , - 'max' => 'The :attribute field should not be greater than :value' , - 'min' => 'The :attribute field should not be less than :value' , - 'size' => 'The field :attribute must be equal to :value' , - 'after' => 'The :attribute field must be larger than the :value field' , - 'before' => 'The :attribute field must be smaller than the :value field' , - 'in' => 'The field :attribute must be equal to one of the values :value' , - 'date' => 'The :attribute must be of date type' , - 'exists' => 'Such :attribute does not exist' , - 'unique' => 'Such :attribute exists' , - 'nationalCode' => 'The national code entered in the :attribute field is incorrect' - ], - - 'attribute' => [ - 'firstName' => 'first name' , - 'lastName' => 'last name' , - 'phone' => 'phone' - ] -]; \ No newline at end of file diff --git a/frameworks/PHP/fomo/routes/api.php b/frameworks/PHP/fomo/routes/api.php deleted file mode 100644 index f711870746d..00000000000 --- a/frameworks/PHP/fomo/routes/api.php +++ /dev/null @@ -1,100 +0,0 @@ -get('/plaintext' , function () { - return response()->withHeaders([ - 'Server' => 'Fomo', - 'Date' => date('D, d M Y H:i:s T'), - ])->plainText('Hello, World!'); -}); - -$router->get('/json' , function () { - return response()->withHeaders([ - 'Server' => 'Fomo', - 'Date' => date('D, d M Y H:i:s T'), - ])->json(['message' => 'Hello, World!']); -}); - -$router->get('/db' , function () { - $id = mt_rand(1, 10000); - // need to pull back a single record from the World table by an $id. - $world = (array) DB::table('World')->where('id', '=', $id)->get()->toArray()[0]; - return response()->withHeaders([ - 'Server' => 'Fomo', - 'Date' => date('D, d M Y H:i:s T'), - ])->json($world); -}); - -$router->get('/fortunes' , function () { - - //$table = DB::table('World'); - $fortunes = DB::table('Fortune')->get()->toArray(); - - $fortune = new \stdClass(); - $fortune->id = 0; - $fortune->message = 'Additional fortune added at request time.'; - array_unshift($fortunes, $fortune); - - // sort the fortunes by message - usort($fortunes, function($a, $b) { - return $a->message <=> $b->message; - }); - - ob_start(); - include(storagePath('view/fortunes.php')); - $html = ob_get_clean(); - - return response()->withHeaders([ - 'Server' => 'Fomo', - 'Date' => date('D, d M Y H:i:s T'), - ])->html($html); -}); - -$router->get('/query' , function () { - $request = Request::getInstance(); - $queries = $request->get('queries'); - if (is_numeric($queries)) { - $queries = max(1, min($queries, 500)); - } else { - $queries = 1; - } - - $worlds = []; - for ($i = 0; $i < $queries; ++$i) { - $random_id = mt_rand(1, 10000); - $world = (array) DB::table('World')->where('id', '=', $random_id)->get()->toArray()[0]; - $worlds[] = $world; - } - return response()->withHeaders([ - 'Server' => 'Fomo', - 'Date' => date('D, d M Y H:i:s T'), - ])->json($worlds); -}); - -$router->get('/update' , function () { - $request = Request::getInstance(); - $queries = $request->get('queries'); - if (is_numeric($queries)) { - $queries = max(1, min($queries, 500)); - } else { - $queries = 1; - } - - $worlds = []; - for ($i = 0; $i < $queries; ++$i) { - $random_id = mt_rand(1, 10000); - $random_number = mt_rand(1, 10000); - $world = (array) DB::table('World')->where('id', '=', $random_id)->get()->toArray()[0]; - DB::table('World')->where('id', '=', $world['id'])->update(['randomNumber' => $random_number]); - $world['randomNumber'] = $random_number; - $worlds[] = $world; - } - return response()->withHeaders([ - 'Server' => 'Fomo', - 'Date' => date('D, d M Y H:i:s T'), - ])->json($worlds); -}); \ No newline at end of file diff --git a/frameworks/PHP/fomo/storage/logs/.keep b/frameworks/PHP/fomo/storage/logs/.keep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/fomo/storage/routes/.keep b/frameworks/PHP/fomo/storage/routes/.keep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/PHP/fomo/storage/view/fortunes.php b/frameworks/PHP/fomo/storage/view/fortunes.php deleted file mode 100644 index 3b1b2c99b5e..00000000000 --- a/frameworks/PHP/fomo/storage/view/fortunes.php +++ /dev/null @@ -1,18 +0,0 @@ - - - Fortunes - - - - - - - - - - - - -
idmessage
id ?>message) ?>
- - diff --git a/frameworks/PHP/hhvm/README.md b/frameworks/PHP/hhvm/README.md deleted file mode 100644 index b19340590a1..00000000000 --- a/frameworks/PHP/hhvm/README.md +++ /dev/null @@ -1,53 +0,0 @@ -#HHVM Benchmarking Test - -This is the [HHVM](http://github.com/facebook/hhvm) portion of a [benchmarking test suite](../) - -Supports the Following Benmarking URLs - -* http://localhost:8080/json.php -* http://localhost:8080/db.php -* http://localhost:8080/db.php?queries=10 -* http://localhost:8080/queries.php -* http://localhost:8080/queries.php?queries=10 -* http://localhost:8080/fortunes.php -* http://localhost:8080/updates.php -* http://localhost:8080/updates.php?queries=10 -* http://localhost:8080/plaintext.php - -### 1. Plaintext Test - -* [Plaintext - source](plaintext.php) - -### 2. Single database query - -* [Single database query - source](db.php) - -### 3. Multiple database queries - -* [Multiple database queries - source](queries.php) - -### 4. Fortune test - -* [Fortunes - source](fortunes.php) - -### 5. Database updates test - -* [Database updates - source](updates.php) - -### 6. Plaintext test - -* [Plaintext - source](plaintext.php) - -## Infrastructure Software Versions -The tests were run with: - -* [HHVM v2.2.0](http://github.com/facebook/hhvm) - -## Setting up a test environment - -1. Invoke the ./setup.sh script - -2. Invoke the ./run.sh script in another terminal - -3. Invoke the ./tests.sh script and see that you get a sample output from all - the urls mentions in the ./URLs file diff --git a/frameworks/PHP/hhvm/URLs b/frameworks/PHP/hhvm/URLs deleted file mode 100644 index ad5570d315c..00000000000 --- a/frameworks/PHP/hhvm/URLs +++ /dev/null @@ -1,10 +0,0 @@ -http://localhost:8080/json.php -http://localhost:8080/db.php -http://localhost:8080/db.php?queries=10 -http://localhost:8080/queries.php -http://localhost:8080/queries.php?queries=10 -http://localhost:8080/fortunes.php -http://localhost:8080/updates.php -http://localhost:8080/updates.php?queries=10 -http://localhost:8080/plaintext.php - diff --git a/frameworks/PHP/hhvm/benchmark_config.json b/frameworks/PHP/hhvm/benchmark_config.json deleted file mode 100644 index 1abb01d30a4..00000000000 --- a/frameworks/PHP/hhvm/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "hhvm", - "tests": - [{ - "default": { - "json_url" : "/json.php", - "db_url" : "/db.php", - "query_url" : "/queries.php?queries=", - "fortune_url" : "/fortunes.php", - "update_url" : "/updates.php?queries=", - "plaintext_url" : "/plaintext.php", - "port" : 8080, - "approach" : "Realistic", - "classification" : "Platform", - "database" : "MySQL", - "framework" : "hhvm", - "language" : "PHP", - "flavor" : "HHVM", - "orm" : "Raw", - "platform" : "None", - "webserver" : "nginx", - "os" : "Linux", - "database_os" : "Linux", - "display_name" : "hhvm", - "notes" : "", - "versus" : "php", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/PHP/hhvm/config.toml b/frameworks/PHP/hhvm/config.toml deleted file mode 100644 index 63fcfd1427d..00000000000 --- a/frameworks/PHP/hhvm/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "hhvm" - -[main] -urls.plaintext = "/plaintext.php" -urls.json = "/json.php" -urls.db = "/db.php" -urls.query = "/queries.php?queries=" -urls.update = "/updates.php?queries=" -urls.fortune = "/fortunes.php" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "nginx" -versus = "php" diff --git a/frameworks/PHP/hhvm/db.php b/frameworks/PHP/hhvm/db.php deleted file mode 100644 index cc668278117..00000000000 --- a/frameworks/PHP/hhvm/db.php +++ /dev/null @@ -1,13 +0,0 @@ -bench_db(); -} - -main(); diff --git a/frameworks/PHP/hhvm/deploy/config-debug.hdf b/frameworks/PHP/hhvm/deploy/config-debug.hdf deleted file mode 100644 index 793b1f9071d..00000000000 --- a/frameworks/PHP/hhvm/deploy/config-debug.hdf +++ /dev/null @@ -1,50 +0,0 @@ -# Debugging configuration file - -# Application PID File -PidFile = /hhvm_app/hhvm.pid - -# Server settings -Server { - FileSocket = /hhvm_app/hhvm.sock - Type = fastcgi - SourceRoot = /hhvm_app - DefaultDocument = index.php - GzipCompressionLevel = 0 - EnableKeepAlive = true - AllowRunAsRoot = 1 -} - -# Enable debug logging -Log { - UseLogFile = true - UseSyslog = false - Level = Verbose - File = /hhvm_app/error.log -} - -# Enable jit for production mode -Eval { - Jit = true - CheckSymLink = false -} - -# Repo file -Repo { - Central { - Path = /hhvm_app/.hhvm.hhbc - } -} - -# Setup basic rewrite -VirtualHost { - * { - Pattern = .* - RewriteRules { - * { - pattern = ^(.*)$ - to = $1.php - qsa = true - } - } - } -} diff --git a/frameworks/PHP/hhvm/deploy/config.hdf b/frameworks/PHP/hhvm/deploy/config.hdf deleted file mode 100755 index 87516873e17..00000000000 --- a/frameworks/PHP/hhvm/deploy/config.hdf +++ /dev/null @@ -1,50 +0,0 @@ -# main configuration file - -# Application PID File -PidFile = /hhvm_app/hhvm.pid - -# Server settings -Server { - FileSocket = /hhvm_app/hhvm.sock - Type = fastcgi - SourceRoot = /hhvm_app - DefaultDocument = index.php - GzipCompressionLevel = 0 - EnableKeepAlive = true - AllowRunAsRoot = 1 -} - -# Disable logging completely -Log { - UseLogFile = false - UseSyslog = false - Level = Error - #File = /hhvm_app/error.log -} - -# Enable jit for production mode -Eval { - Jit = true - CheckSymLink = false -} - -# Repo file -Repo { - Central { - Path = /hhvm_app/.hhvm.hhbc - } -} - -# Setup basic rewrite -VirtualHost { - * { - Pattern = .* - RewriteRules { - * { - pattern = ^(.*)$ - to = $1.php - qsa = true - } - } - } -} diff --git a/frameworks/PHP/hhvm/deploy/nginx.conf b/frameworks/PHP/hhvm/deploy/nginx.conf deleted file mode 100755 index bf2a5ecdde9..00000000000 --- a/frameworks/PHP/hhvm/deploy/nginx.conf +++ /dev/null @@ -1,36 +0,0 @@ -user root; -worker_processes auto; -error_log stderr error; -worker_rlimit_nofile 200000; - -events { - worker_connections 16384; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - access_log off; - server_tokens off; - - sendfile on; - keepalive_timeout 65; - - upstream fastcgi_backend { - server unix:/hhvm_app/hhvm.sock; - keepalive 40; - } - - server { - listen 8080; - server_name localhost; - location ~ \.(hh|php)$ { - root /hhvm_app; - fastcgi_keep_conn on; - fastcgi_pass fastcgi_backend; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include /etc/nginx/fastcgi_params; - } - } -} diff --git a/frameworks/PHP/hhvm/fortunes.php b/frameworks/PHP/hhvm/fortunes.php deleted file mode 100644 index b1806dfb427..00000000000 --- a/frameworks/PHP/hhvm/fortunes.php +++ /dev/null @@ -1,13 +0,0 @@ -bench_fortunes(); -} - -main(); diff --git a/frameworks/PHP/hhvm/hhvm.dockerfile b/frameworks/PHP/hhvm/hhvm.dockerfile deleted file mode 100644 index 8e31e14a2c4..00000000000 --- a/frameworks/PHP/hhvm/hhvm.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:19.04 - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update -yqq && apt-get install -yqq software-properties-common apt-transport-https > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -RUN apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xB4112585D386EB94 -RUN add-apt-repository https://dl.hhvm.com/ubuntu -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq hhvm nginx git unzip php7.3 php7.3-common php7.3-cli php7.3-fpm php7.3-mysql php7.3-xml php7.3-mbstring php7.3-mongodb > /dev/null - -ADD ./ /hhvm_app -WORKDIR /hhvm_app - -EXPOSE 8080 - -CMD hhvm -m daemon --config /hhvm_app/deploy/config.hdf && \ - nginx -c /hhvm_app/deploy/nginx.conf -g "daemon off;" diff --git a/frameworks/PHP/hhvm/json.php b/frameworks/PHP/hhvm/json.php deleted file mode 100644 index df77cf9474b..00000000000 --- a/frameworks/PHP/hhvm/json.php +++ /dev/null @@ -1,13 +0,0 @@ -bench_json(); -} - -main(); diff --git a/frameworks/PHP/hhvm/once.php.inc b/frameworks/PHP/hhvm/once.php.inc deleted file mode 100644 index d946aa70a02..00000000000 --- a/frameworks/PHP/hhvm/once.php.inc +++ /dev/null @@ -1,146 +0,0 @@ -pdo = new PDO( - 'mysql:host=tfb-database;dbname=hello_world;charset=utf8', - 'benchmarkdbuser', - 'benchmarkdbpass', - array(PDO::ATTR_PERSISTENT => true)); - } - - public function bench_json() - { - header('Content-Type: application/json'); - echo json_encode(array('message' => 'Hello, World!')); - } - - public function bench_plaintext() - { - header('Content-Type: text/plain; charset=utf-8'); - echo 'Hello, World!'; - } - - public function bench_db() - { - $this->setup_db(); - - $id = mt_rand(1, 10000); - - // Define query - $statement = $this->pdo->prepare('SELECT id, randomNumber FROM World WHERE id = :id'); - $statement->bindParam(':id', $id, PDO::PARAM_INT); - $statement->execute(); - - // Store result in array. - $arr = array('id' => $id, 'randomNumber' => $statement->fetchColumn()); - - // Send the required parameters - header('Content-Type: application/json'); - echo json_encode($arr); - } - - public function bench_queries($query_count=1) - { - $this->setup_db(); - - // Create an array with the response string. - $arr = array(); - $id = mt_rand(1, 10000); - - // Define query - $statement = $this->pdo->prepare('SELECT id, randomNumber FROM World WHERE id = :id'); - $statement->bindParam(':id', $id, PDO::PARAM_INT); - - // For each query, store the result set values in the response array - while (0 < $query_count--) { - $statement->execute(); - - // Store result in array. - $arr[] = array('id' => $id, 'randomNumber' => $statement->fetchColumn()); - $id = mt_rand(1, 10000); - } - - // Send the required parameters - header('Content-Type: application/json'); - echo json_encode($arr); - } - - public function bench_updates($query_count) - { - $this->setup_db(); - - // Create an array with the response string. - $arr = array(); - $id = mt_rand(1, 10000); - $randomNumber = mt_rand(1, 1000); - - // Define query - $statement = $this->pdo->prepare('SELECT id, randomNumber FROM World WHERE id = :id'); - $statement->bindParam(':id', $id, PDO::PARAM_INT); - - $updateStatement = $this->pdo->prepare('UPDATE World SET randomNumber = :randomNumber WHERE id = :id'); - $updateStatement->bindParam(':id', $id, PDO::PARAM_INT); - $updateStatement->bindParam(':randomNumber', $randomNumber, PDO::PARAM_INT); - - // For each query, store the result set values in the response array - while (0 < $query_count--) { - $statement->execute(); - - // Store result in array. - $world = array('id' => $id, 'randomNumber' => $statement->fetchColumn()); - $world['randomNumber'] = $randomNumber; - $updateStatement->execute(); - - $arr[] = $world; - $id = mt_rand(1, 10000); - $randomNumber = mt_rand(1, 10000); - } - - // Send the required parameters - header('Content-Type: application/json'); - echo json_encode($arr); - } - - public function bench_fortunes() - { - $this->setup_db(); - - // Define query - $statement = $this->pdo->query( 'SELECT id, message FROM Fortune' ); - - // Store result in array. - $arr = $statement->fetchAll(PDO::FETCH_KEY_PAIR); - $arr[0] = 'Additional fortune added at request time.'; - - asort($arr); - header("Content-Type: text/html; charset=utf-8"); - echo << - - -Fortunes - - - - - - - -EOM; - foreach ( $arr as $id => $fortune ) { - echo ''; - echo ''; - echo ''; - echo ''; - } -echo << - - -EOM; - } -} diff --git a/frameworks/PHP/hhvm/plaintext.php b/frameworks/PHP/hhvm/plaintext.php deleted file mode 100644 index dc887c228f5..00000000000 --- a/frameworks/PHP/hhvm/plaintext.php +++ /dev/null @@ -1,13 +0,0 @@ -bench_plaintext(); -} - -main(); diff --git a/frameworks/PHP/hhvm/queries.php b/frameworks/PHP/hhvm/queries.php deleted file mode 100644 index 5807d3d60a8..00000000000 --- a/frameworks/PHP/hhvm/queries.php +++ /dev/null @@ -1,22 +0,0 @@ - 500 ? 500 : $query_count); - - $b = new Benchmark(); - $b->bench_queries($query_count); -} - -main(); diff --git a/frameworks/PHP/hhvm/updates.php b/frameworks/PHP/hhvm/updates.php deleted file mode 100644 index cd2fbfb1c03..00000000000 --- a/frameworks/PHP/hhvm/updates.php +++ /dev/null @@ -1,22 +0,0 @@ - 500 ? 500 : $query_count); - - $b = new Benchmark(); - $b->bench_updates($query_count); -} - -main(); diff --git a/frameworks/PHP/hypervel/benchmark_config.json b/frameworks/PHP/hypervel/benchmark_config.json index fae8242ba6f..90fbc96b99a 100644 --- a/frameworks/PHP/hypervel/benchmark_config.json +++ b/frameworks/PHP/hypervel/benchmark_config.json @@ -12,7 +12,7 @@ "approach": "Realistic", "classification": "Fullstack", "database": "MySQL", - "framework": "lypervel", + "framework": "hypervel", "language": "PHP", "flavor": "PHP8", "orm": "Full", diff --git a/frameworks/PHP/hypervel/composer.json b/frameworks/PHP/hypervel/composer.json index d877dcae4e7..817c831eb6c 100644 --- a/frameworks/PHP/hypervel/composer.json +++ b/frameworks/PHP/hypervel/composer.json @@ -15,20 +15,7 @@ "require": { "php": ">=8.2", "friendsofhyperf/tinker": "~3.1.0", - "hypervel/framework": "^0.2" - }, - "require-dev": { - "fakerphp/faker": "^1.24.1", - "filp/whoops": "^2.15", - "friendsofphp/php-cs-fixer": "^3.57.2", - "hyperf/testing": "~3.1.0", - "hyperf/watcher": "~3.1.0", - "hypervel/devtool": "^0.2", - "mockery/mockery": "1.6.x-dev", - "nunomaduro/collision": "^8.5", - "phpstan/phpstan": "^1.11.5", - "phpunit/phpunit": "10.5.45", - "swoole/ide-helper": "~5.1.0" + "hypervel/framework": "^0.3" }, "autoload": { "psr-4": { @@ -36,14 +23,6 @@ }, "files": [] }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - }, - "files": [ - "tests/helpers.php" - ] - }, "minimum-stability": "dev", "prefer-stable": true, "suggest": { diff --git a/frameworks/PHP/hypervel/config/database.php b/frameworks/PHP/hypervel/config/database.php index 14f2b3ae2b4..3d2bb3a005f 100644 --- a/frameworks/PHP/hypervel/config/database.php +++ b/frameworks/PHP/hypervel/config/database.php @@ -32,7 +32,7 @@ 'prefix' => env('DB_PREFIX', ''), 'pool' => [ 'min_connections' => 1, - 'max_connections' => env('DB_MAX_CONNECTIONS', 10), + 'max_connections' => env('DB_MAX_CONNECTIONS', 60), 'connect_timeout' => 10.0, 'wait_timeout' => 3.0, 'heartbeat' => -1, diff --git a/frameworks/PHP/hypervel/config/server.php b/frameworks/PHP/hypervel/config/server.php index 8fe740d8b54..22e2d930262 100644 --- a/frameworks/PHP/hypervel/config/server.php +++ b/frameworks/PHP/hypervel/config/server.php @@ -31,8 +31,9 @@ Constant::OPTION_WORKER_NUM => env('SERVER_WORKERS_NUMBER', swoole_cpu_num()), Constant::OPTION_PID_FILE => base_path('runtime/hypervel.pid'), Constant::OPTION_OPEN_TCP_NODELAY => true, + Constant::OPTION_HTTP_COMPRESSION => false, Constant::OPTION_MAX_COROUTINE => 100000, - Constant::OPTION_OPEN_HTTP2_PROTOCOL => true, + Constant::OPTION_OPEN_HTTP2_PROTOCOL => false, Constant::OPTION_MAX_REQUEST => 100000, Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024, Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024, diff --git a/frameworks/PHP/hypervel/hypervel.dockerfile b/frameworks/PHP/hypervel/hypervel.dockerfile index 8001546aab4..2957bd02354 100644 --- a/frameworks/PHP/hypervel/hypervel.dockerfile +++ b/frameworks/PHP/hypervel/hypervel.dockerfile @@ -1,6 +1,6 @@ -FROM phpswoole/swoole:php8.4 +FROM phpswoole/swoole:php8.5 -RUN docker-php-ext-install pcntl opcache curl > /dev/null +RUN docker-php-ext-install pcntl > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini diff --git a/frameworks/PHP/hypervel/phpunit.xml.dist b/frameworks/PHP/hypervel/phpunit.xml.dist deleted file mode 100644 index b151c4877dd..00000000000 --- a/frameworks/PHP/hypervel/phpunit.xml.dist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - tests/Unit - - - tests/Feature - - - - - app - - - - - - - - - diff --git a/frameworks/PHP/hypervel/tests/Feature/ExampleTest.php b/frameworks/PHP/hypervel/tests/Feature/ExampleTest.php deleted file mode 100644 index f452242de10..00000000000 --- a/frameworks/PHP/hypervel/tests/Feature/ExampleTest.php +++ /dev/null @@ -1,20 +0,0 @@ -get('/') - ->assertSuccessful(); - } -} diff --git a/frameworks/PHP/hypervel/tests/Feature/RefreshDatabaseTest.php b/frameworks/PHP/hypervel/tests/Feature/RefreshDatabaseTest.php deleted file mode 100644 index 54f41f938a3..00000000000 --- a/frameworks/PHP/hypervel/tests/Feature/RefreshDatabaseTest.php +++ /dev/null @@ -1,39 +0,0 @@ -create(); - - $this->assertDatabaseHas('users', [ - 'id' => $user->id, - ]); - } - - public function testCreateMultipleUsers() - { - factory(User::class, $count = 5)->create(); - - $this->assertDatabaseCount('users', $count); - } - - public function testZeroUserAfterRefresh() - { - $this->assertSame(0, User::count()); - } -} diff --git a/frameworks/PHP/hypervel/tests/TestCase.php b/frameworks/PHP/hypervel/tests/TestCase.php deleted file mode 100644 index 754c7277ca5..00000000000 --- a/frameworks/PHP/hypervel/tests/TestCase.php +++ /dev/null @@ -1,13 +0,0 @@ -assertTrue(true); - } -} diff --git a/frameworks/PHP/hypervel/tests/bootstrap.php b/frameworks/PHP/hypervel/tests/bootstrap.php deleted file mode 100644 index d5afa4a9b22..00000000000 --- a/frameworks/PHP/hypervel/tests/bootstrap.php +++ /dev/null @@ -1,38 +0,0 @@ -get(Hyperf\Contract\ApplicationInterface::class); diff --git a/frameworks/PHP/hypervel/tests/helpers.php b/frameworks/PHP/hypervel/tests/helpers.php deleted file mode 100644 index cbd0f353a0a..00000000000 --- a/frameworks/PHP/hypervel/tests/helpers.php +++ /dev/null @@ -1,15 +0,0 @@ -get(ModelFactory::class) - ->factory($class, ...$arguments); - } -} diff --git a/frameworks/PHP/imi/benchmark_config.json b/frameworks/PHP/imi/benchmark_config.json index 631dff1462c..4b2d82f46f8 100644 --- a/frameworks/PHP/imi/benchmark_config.json +++ b/frameworks/PHP/imi/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "imi", + "maintainers": ["Yurunsoft"], "tests": [ { "default": { diff --git a/frameworks/PHP/imi/imi-swoole.dockerfile b/frameworks/PHP/imi/imi-swoole.dockerfile index 2cc80f2b982..698f0b043b0 100644 --- a/frameworks/PHP/imi/imi-swoole.dockerfile +++ b/frameworks/PHP/imi/imi-swoole.dockerfile @@ -1,30 +1,19 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1-php8.3 -ENV SWOOLE_VERSION 5.1.1 ARG TFB_TEST_DATABASE ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE} -RUN apt -yqq update && \ - apt upgrade -y && \ - apt -yqq install git unzip libpq-dev +RUN docker-php-ext-install -j$(nproc) opcache mysqli > /dev/null -RUN docker-php-ext-install -j$(nproc) pdo_pgsql opcache mysqli - -RUN cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ - && cd swoole-src-${SWOOLE_VERSION} \ - && phpize && ./configure --enable-swoole-pgsql && make -j install \ - && docker-php-ext-enable swoole +WORKDIR /imi +COPY . . -COPY . /imi COPY php.ini /usr/local/etc/php/ RUN chmod -R ug+rwx /imi/.runtime -WORKDIR /imi - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --no-dev --classmap-authoritative --quiet -RUN composer require imiphp/imi-swoole:~2.1.0 -W +RUN composer require imiphp/imi-swoole:~2.1.0 -W --quiet RUN composer dumpautoload -o EXPOSE 8080 diff --git a/frameworks/PHP/imi/imi-workerman.dockerfile b/frameworks/PHP/imi/imi-workerman.dockerfile index 306a2512a82..2070bf12ff4 100644 --- a/frameworks/PHP/imi/imi-workerman.dockerfile +++ b/frameworks/PHP/imi/imi-workerman.dockerfile @@ -1,29 +1,29 @@ FROM php:8.3-cli +ARG DEBIAN_FRONTEND=noninteractive + ARG TFB_TEST_DATABASE ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE} -RUN apt -yqq update && \ - apt upgrade -y && \ - apt -yqq install git unzip libevent-dev libssl-dev libpq-dev - -RUN docker-php-ext-install -j$(nproc) opcache mysqli pcntl sockets pdo_pgsql +RUN apt -yqq update > /dev/null && \ + apt upgrade -y > /dev/null && \ + apt -yqq install git unzip libevent-dev libssl-dev libpq-dev > /dev/null -RUN pecl update-channels +RUN docker-php-ext-install -j$(nproc) opcache mysqli pcntl sockets pdo_pgsql > /dev/null -RUN pecl install event && \ +RUN pecl install event-3.1.4 > /dev/null && \ echo "extension=event.so" > /usr/local/etc/php/conf.d/event.ini -COPY . /imi +WORKDIR /imi +COPY . . + COPY php.ini /usr/local/etc/php/ RUN chmod -R ug+rwx /imi/.runtime -WORKDIR /imi - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer RUN composer install --no-dev --classmap-authoritative --quiet -RUN composer require imiphp/imi-workerman:~2.1.0 -W +RUN composer require imiphp/imi-workerman:~2.1.0 -W --quiet RUN composer dumpautoload -o EXPOSE 8080 diff --git a/frameworks/PHP/laravel/composer.json b/frameworks/PHP/laravel/composer.json index be731270c67..29c4ecbd314 100644 --- a/frameworks/PHP/laravel/composer.json +++ b/frameworks/PHP/laravel/composer.json @@ -39,7 +39,8 @@ "symfony/polyfill-php81": "*", "symfony/polyfill-php82": "*", "symfony/polyfill-php83": "*", - "symfony/polyfill-php84": "*" + "symfony/polyfill-php84": "*", + "symfony/polyfill-php85": "*" }, "minimum-stability": "stable", "prefer-stable": true, diff --git a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile index 5cc47e90375..4bb37bb39da 100644 --- a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile +++ b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile @@ -1,11 +1,9 @@ -FROM phpswoole/swoole:php8.4 +FROM phpswoole/swoole:php8.5 RUN apt-get -y update > /dev/null \ && apt-get install -y libicu-dev > /dev/null \ && docker-php-ext-configure intl > /dev/null \ - && docker-php-ext-install intl > /dev/null - -RUN docker-php-ext-install pcntl opcache curl > /dev/null + && docker-php-ext-install intl pcntl > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini diff --git a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile index dc2e4724395..3832de1ea97 100644 --- a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile +++ b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile @@ -10,7 +10,7 @@ RUN install-php-extensions \ zip > /dev/null COPY --link . /app/ -COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer RUN mkdir -p bootstrap/cache \ storage/logs \ @@ -20,7 +20,7 @@ RUN mkdir -p bootstrap/cache \ COPY --link deploy/franken/php.ini /usr/local/etc/php -RUN composer require laravel/octane guzzlehttp/guzzle --update-no-dev --no-scripts --quiet +RUN composer require laravel/octane:^2 guzzlehttp/guzzle --update-no-dev --no-scripts --quiet RUN php artisan optimize RUN frankenphp -v diff --git a/frameworks/PHP/laravel/laravel-ripple.dockerfile b/frameworks/PHP/laravel/laravel-ripple.dockerfile index 101b458a051..0c84e30fed0 100644 --- a/frameworks/PHP/laravel/laravel-ripple.dockerfile +++ b/frameworks/PHP/laravel/laravel-ripple.dockerfile @@ -24,7 +24,7 @@ RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opca RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini -COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer # Initialize WORKDIR /laravel diff --git a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile index 44c97267c12..db9d2e4d28e 100644 --- a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile +++ b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile @@ -24,9 +24,9 @@ RUN apt-get update > /dev/null && \ RUN pecl install protobuf > /dev/null && echo "extension=protobuf.so" > /usr/local/etc/php/conf.d/protobuf.ini -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer -RUN composer require laravel/octane --update-no-dev --no-scripts --quiet +RUN composer require laravel/octane:^2 --update-no-dev --no-scripts --quiet RUN php artisan octane:install --server="roadrunner" > /dev/null RUN php artisan optimize diff --git a/frameworks/PHP/laravel/laravel-swoole.dockerfile b/frameworks/PHP/laravel/laravel-swoole.dockerfile index ae51b9d0ad1..32556859b64 100644 --- a/frameworks/PHP/laravel/laravel-swoole.dockerfile +++ b/frameworks/PHP/laravel/laravel-swoole.dockerfile @@ -1,7 +1,7 @@ -FROM phpswoole/swoole:php8.4 +FROM phpswoole/swoole:php8.5 -RUN apt-get update -yqq && apt-get install libicu-dev -y > /dev/null -RUN docker-php-ext-install intl pcntl opcache > /dev/null +RUN apt-get update -yqq && apt-get install libicu-dev -y > /dev/null && \ + docker-php-ext-install intl pcntl > /dev/null RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit=1205" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini @@ -15,7 +15,7 @@ RUN mkdir -p bootstrap/cache \ storage/framework/views \ storage/framework/cache -RUN composer require laravel/octane:2.11 --update-no-dev --no-scripts --quiet +RUN composer require laravel/octane:^2 --update-no-dev --no-scripts --quiet RUN php artisan octane:install --server="swoole" RUN php artisan optimize diff --git a/frameworks/PHP/laravel/laravel-workerman.dockerfile b/frameworks/PHP/laravel/laravel-workerman.dockerfile index a9cd1313cc7..a9ee0d87a70 100644 --- a/frameworks/PHP/laravel/laravel-workerman.dockerfile +++ b/frameworks/PHP/laravel/laravel-workerman.dockerfile @@ -3,12 +3,12 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ - apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null && \ +RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null && \ + apt-get upgrade -yqq > /dev/null && \ apt-get install -yqq git unzip \ php8.5-cli php8.5-mysql php8.5-mbstring php8.5-xml php8.5-intl php8.5-curl > /dev/null -COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini diff --git a/frameworks/PHP/laravel/laravel.dockerfile b/frameworks/PHP/laravel/laravel.dockerfile index 46d5aca59cc..8d0687cf6f3 100644 --- a/frameworks/PHP/laravel/laravel.dockerfile +++ b/frameworks/PHP/laravel/laravel.dockerfile @@ -3,13 +3,17 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ - apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null && \ + apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq nginx git unzip \ php8.5-bcmath php8.5-cli php8.5-fpm php8.5-mysql php8.5-mbstring php8.5-xml php8.5-curl php8.5-intl > /dev/null -COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer +# Use Jemalloc for optimize +RUN apt install libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /laravel diff --git a/frameworks/PHP/laravel/opcache_preload.php b/frameworks/PHP/laravel/opcache_preload.php index 687af36e6b9..5843addb5a2 100644 --- a/frameworks/PHP/laravel/opcache_preload.php +++ b/frameworks/PHP/laravel/opcache_preload.php @@ -1,3 +1,156 @@ paths( + __DIR__ . '/vendor/laravel', + __DIR__ . '/vendor/symfony', + __DIR__ . '/vendor/nesbot/carbon', + __DIR__ . '/vendor/vlucas/phpdotenv', + ) + ->ignore( + 'Laravel\Telescope', + 'Laravel\Tinker', + 'Illuminate\Queue', + 'Illuminate\Contracts\Queue', + 'Illuminate\View', + 'Illuminate\Contracts\View', + 'Illuminate\Foundation\Console', + 'Illuminate\Notification', + 'Illuminate\Contracts\Notifications', + 'Illuminate\Bus', + 'Illuminate\Session', + 'Illuminate\Contracts\Session', + 'Illuminate\Console', + 'Illuminate\Testing', + 'Illuminate\Http\Testing', + 'Illuminate\Support\Testing', + 'Illuminate\Cookie', + 'Illuminate\Contracts\Cookie', + 'Illuminate\Broadcasting', + 'Illuminate\Contracts\Broadcasting', + 'Illuminate\Mail', + 'Illuminate\Contracts\Mail', + ) + ->load(); + +class Preloader +{ + private array $ignores = []; + + private static int $count = 0; + + private array $paths; + + private array $fileMap; + + public function __construct(string ...$paths) + { + $this->paths = $paths; + + // We'll use composer's classmap + // to easily find which classes to autoload, + // based on their filename + $classMap = require __DIR__ . '/vendor/composer/autoload_classmap.php'; + + $this->fileMap = array_flip($classMap); + } + + public function paths(string ...$paths): Preloader + { + $this->paths = array_merge( + $this->paths, + $paths + ); + + return $this; + } + + public function ignore(string ...$names): Preloader + { + $this->ignores = array_merge( + $this->ignores, + $names + ); + + return $this; + } + + public function load(): void + { + // We'll loop over all registered paths + // and load them one by one + foreach ($this->paths as $path) { + $this->loadPath(rtrim($path, '/')); + } + + $count = self::$count; + + echo "[Preloader] Preloaded {$count} classes" . PHP_EOL; + } + + private function loadPath(string $path): void + { + // If the current path is a directory, + // we'll load all files in it + if (is_dir($path)) { + $this->loadDir($path); + + return; + } + + // Otherwise we'll just load this one file + $this->loadFile($path); + } + + private function loadDir(string $path): void + { + $handle = opendir($path); + + // We'll loop over all files and directories + // in the current path, + // and load them one by one + while ($file = readdir($handle)) { + if (in_array($file, ['.', '..'])) { + continue; + } + + $this->loadPath("{$path}/{$file}"); + } + + closedir($handle); + } + + private function loadFile(string $path): void + { + // We resolve the classname from composer's autoload mapping + $class = $this->fileMap[$path] ?? null; + + // And use it to make sure the class shouldn't be ignored + if ($this->shouldIgnore($class)) { + return; + } + + // Finally we require the path, + // causing all its dependencies to be loaded as well + opcache_compile_file($path); + + self::$count++; + + echo "[Preloader] Preloaded `{$class}`" . PHP_EOL; + } + + private function shouldIgnore(?string $name): bool + { + if ($name === null) { + return true; + } + + foreach ($this->ignores as $ignore) { + if (str_starts_with($name, $ignore)) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/frameworks/PHP/mixphp/benchmark_config.json b/frameworks/PHP/mixphp/benchmark_config.json index 0b12c37bc7d..155aaff2b2a 100644 --- a/frameworks/PHP/mixphp/benchmark_config.json +++ b/frameworks/PHP/mixphp/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "mixphp", + "maintainers": ["onanying"], "tests": [ { "default": { diff --git a/frameworks/PHP/mixphp/composer.json b/frameworks/PHP/mixphp/composer.json index 7f5766c4164..1f81196f165 100644 --- a/frameworks/PHP/mixphp/composer.json +++ b/frameworks/PHP/mixphp/composer.json @@ -17,7 +17,7 @@ ] }, "require": { - "workerman/workerman": "^4.0", + "workerman/workerman": "^5.0", "mix/vega": "~3.0", "mix/database": "~3.0", "monolog/monolog": "^2.3" diff --git a/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile b/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile index ce9292f244a..d3d6e26939a 100644 --- a/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile @@ -1,6 +1,4 @@ -FROM phpswoole/swoole:6.0.2-php8.4 - -RUN docker-php-ext-install pcntl opcache bcmath > /dev/null +FROM phpswoole/swoole:php8.5 WORKDIR /mixphp COPY --link . . @@ -13,7 +11,7 @@ RUN echo "opcache.jit_buffer_size=256M" >> /usr/local/etc/php/php.ini RUN php -v && php -i | grep opcache -RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null +RUN composer install --no-dev --classmap-authoritative --quiet RUN composer dumpautoload -o RUN mkdir -p /mixphp/runtime/logs diff --git a/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile b/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile index c2a282a9611..7fa0d550bab 100644 --- a/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile @@ -3,20 +3,19 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -RUN apt-get update -yqq && apt-get install -yqq git unzip wget curl build-essential php8.4-cli php8.4-mbstring php8.4-curl php8.4-xml php8.4-mysql > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null +RUN apt-get update -yqq && apt-get install -yqq git curl php8.5-cli php8.5-mbstring php8.5-curl php8.5-xml php8.5-mysql > /dev/null -RUN apt-get install -y php8.4-dev libevent-dev > /dev/null -RUN wget http://pear.php.net/go-pear.phar --quiet && php go-pear.phar -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY php-jit.ini /etc/php/8.4/cli/php.ini +COPY php-jit.ini /etc/php/8.5/cli/php.ini -ADD ./ /mixphp WORKDIR /mixphp +COPY . . -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer +RUN composer install --no-dev --classmap-authoritative --quiet RUN composer dumpautoload -o RUN mkdir -p /mixphp/runtime/logs diff --git a/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile b/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile index 85143701159..df7143d7bb1 100644 --- a/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile @@ -3,22 +3,21 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -RUN apt-get update -yqq && apt-get install -yqq git unzip wget curl build-essential php8.4-cli php8.4-mbstring php8.4-curl php8.4-xml php8.4-pgsql > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null +RUN apt-get update -yqq && apt-get install -yqq git curl php8.5-cli php8.5-mbstring php8.5-curl php8.5-xml php8.5-pgsql > /dev/null -RUN apt-get install -y php8.4-dev libevent-dev > /dev/null -RUN wget http://pear.php.net/go-pear.phar --quiet && php go-pear.phar -RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini +RUN apt-get install -y php8.5-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini -COPY php-jit.ini /etc/php/8.4/cli/php.ini +COPY php-jit.ini /etc/php/8.5/cli/php.ini -ADD ./ /mixphp WORKDIR /mixphp +COPY . . RUN sed -i "s|Benchmark();|BenchmarkRaw();|g" /mixphp/routes/index.php -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer +RUN composer install --no-dev --classmap-authoritative --quiet RUN composer dumpautoload -o RUN mkdir -p /mixphp/runtime/logs diff --git a/frameworks/PHP/mixphp/mixphp.dockerfile b/frameworks/PHP/mixphp/mixphp.dockerfile index 360debab252..94f266f0460 100644 --- a/frameworks/PHP/mixphp/mixphp.dockerfile +++ b/frameworks/PHP/mixphp/mixphp.dockerfile @@ -3,18 +3,18 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -RUN apt-get update -yqq && apt-get install -yqq git unzip wget curl build-essential nginx php8.4-fpm php8.4-mysql php8.4-dev > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null +RUN apt-get update -yqq && apt-get install -yqq git curl nginx php8.5-fpm php8.5-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.5/fpm/ -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.5/fpm/php-fpm.conf ; fi; -ADD ./ /mixphp WORKDIR /mixphp +COPY . . -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer +RUN composer install --no-dev --classmap-authoritative --quiet RUN composer dumpautoload -o RUN mkdir -p /mixphp/runtime/logs @@ -22,5 +22,5 @@ RUN chmod -R 777 /mixphp/runtime/logs EXPOSE 8080 -CMD service php8.4-fpm start && \ +CMD service php8.5-fpm start && \ nginx -c /mixphp/deploy/nginx.conf diff --git a/frameworks/PHP/one/benchmark_config.json b/frameworks/PHP/one/benchmark_config.json index f6de6c829aa..2ef5acf431d 100644 --- a/frameworks/PHP/one/benchmark_config.json +++ b/frameworks/PHP/one/benchmark_config.json @@ -23,7 +23,8 @@ "database_os": "Linux", "display_name": "one", "notes": "", - "versus": "swoole" + "versus": "swoole", + "tags": [ "broken" ] }, "no-coroutine": { "json_url": "/json", @@ -46,7 +47,8 @@ "database_os": "Linux", "display_name": "one-no-coroutine", "notes": "", - "versus": "swoole" + "versus": "swoole", + "tags": [ "broken" ] } } ] diff --git a/frameworks/PHP/openswoole/benchmark_config.json b/frameworks/PHP/openswoole/benchmark_config.json index 44084e467c4..396a99f6ddb 100644 --- a/frameworks/PHP/openswoole/benchmark_config.json +++ b/frameworks/PHP/openswoole/benchmark_config.json @@ -14,7 +14,7 @@ "database": "MySQL", "framework": "openswoole", "language": "PHP", - "flavor": "PHP8.2", + "flavor": "PHP8.4", "orm": "Raw", "platform": "openswoole", "webserver": "none", @@ -35,7 +35,7 @@ "database": "Postgres", "framework": "openswoole", "language": "PHP", - "flavor": "PHP8.2", + "flavor": "PHP8.4", "orm": "Raw", "platform": "openswoole", "webserver": "none", @@ -43,7 +43,8 @@ "database_os": "Linux", "display_name": "openswoole Postgres", "notes": "", - "versus": "php" + "versus": "php", + "tags": [ "broken" ] }, "no-async": { "db_url": "/db", @@ -56,7 +57,7 @@ "database": "MySQL", "framework": "openswoole", "language": "PHP", - "flavor": "PHP8.2", + "flavor": "PHP8.4", "orm": "Raw", "platform": "openswoole", "webserver": "none", diff --git a/frameworks/PHP/openswoole/composer.json b/frameworks/PHP/openswoole/composer.json index f71d50109b3..f2a6cfb89f1 100644 --- a/frameworks/PHP/openswoole/composer.json +++ b/frameworks/PHP/openswoole/composer.json @@ -1,5 +1,5 @@ { "require": { - "openswoole/core": "dev-master" + "openswoole/core": "^22.2" } } diff --git a/frameworks/PHP/openswoole/openswoole-no-async.dockerfile b/frameworks/PHP/openswoole/openswoole-no-async.dockerfile index 73762687883..845aa01313c 100644 --- a/frameworks/PHP/openswoole/openswoole-no-async.dockerfile +++ b/frameworks/PHP/openswoole/openswoole-no-async.dockerfile @@ -1,21 +1,17 @@ -FROM php:8.4-cli - -RUN apt-get update && apt-get install -y git > /dev/null +FROM openswoole/swoole:25.2-php8.4 RUN docker-php-ext-install opcache pdo_mysql > /dev/null -RUN pecl install openswoole > /dev/null && \ - docker-php-ext-enable openswoole - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +ENV TINI_SUBREAPER 1 +#ENV DISABLE_DEFAULT_SERVER 1 COPY php.ini /usr/local/etc/php/ -ADD ./ /openswoole -WORKDIR /openswoole +WORKDIR /var/www +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD php /openswoole/openswoole-server-pdo.php +CMD ["php", "/var/www/openswoole-server-pdo.php"] diff --git a/frameworks/PHP/openswoole/openswoole-postgres.dockerfile b/frameworks/PHP/openswoole/openswoole-postgres.dockerfile index 02aa7432b32..f6e697931f3 100644 --- a/frameworks/PHP/openswoole/openswoole-postgres.dockerfile +++ b/frameworks/PHP/openswoole/openswoole-postgres.dockerfile @@ -1,26 +1,19 @@ -FROM php:8.2-cli +FROM openswoole/swoole:25.2-php8.4 -RUN apt-get update && apt-get install -y git > /dev/null +RUN docker-php-ext-install opcache pdo_pgsql > /dev/null -RUN docker-php-ext-install opcache > /dev/null - -ENV VERSION 22.0.0 - -RUN apt-get update && apt-get install -y libpq-dev \ - && cd /tmp && curl -sSL "https://github.com/openswoole/ext-openswoole/archive/v${VERSION}.tar.gz" | tar xzf - \ - && cd ext-openswoole-${VERSION} \ - && phpize && ./configure --with-postgres > /dev/null && make > /dev/null && make install > /dev/null \ - && docker-php-ext-enable openswoole - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +ENV TINI_SUBREAPER 1 +#ENV DISABLE_DEFAULT_SERVER 1 COPY php.ini /usr/local/etc/php/ -ADD ./ /openswoole -WORKDIR /openswoole +WORKDIR /var/www +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD php /openswoole/openswoole-server-postgres.php +RUN php --ri openswoole + +CMD ["php", "/var/www/openswoole-server-postgres.php"] diff --git a/frameworks/PHP/openswoole/openswoole-server-mysql.php b/frameworks/PHP/openswoole/openswoole-server-mysql.php index e020600ce87..2e138c4d38d 100644 --- a/frameworks/PHP/openswoole/openswoole-server-mysql.php +++ b/frameworks/PHP/openswoole/openswoole-server-mysql.php @@ -141,7 +141,7 @@ /** * On every request to the (web)server, execute the following code */ -$server->on('request', static function (Request $req, Response $res) use ($db_mysql, $db_query, $fortunes_mysql, $updates_mysql, &$pool) { +$server->on('request', static function (Request $req, Response $res) use ($db_mysql, $fortunes_mysql, $updates_mysql, &$pool) { try { switch ($req->server['request_uri']) { case '/json': diff --git a/frameworks/PHP/openswoole/openswoole.dockerfile b/frameworks/PHP/openswoole/openswoole.dockerfile index d9d89845e54..2bb8d8afb5d 100644 --- a/frameworks/PHP/openswoole/openswoole.dockerfile +++ b/frameworks/PHP/openswoole/openswoole.dockerfile @@ -1,21 +1,16 @@ -FROM php:8.4-cli - -RUN apt-get update && apt-get install -y git > /dev/null +FROM openswoole/swoole:25.2-php8.4 RUN docker-php-ext-install opcache pdo_mysql > /dev/null -RUN pecl install openswoole > /dev/null && \ - docker-php-ext-enable openswoole - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +ENV TINI_SUBREAPER 1 COPY php.ini /usr/local/etc/php/ -ADD ./ /openswoole -WORKDIR /openswoole +WORKDIR /var/www +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD php /openswoole/openswoole-server-mysql.php +CMD ["php", "/var/www/openswoole-server-mysql.php"] diff --git a/frameworks/PHP/peachpie/benchmark_config.json b/frameworks/PHP/peachpie/benchmark_config.json index a72dcb607f7..f97b0e2b8a9 100644 --- a/frameworks/PHP/peachpie/benchmark_config.json +++ b/frameworks/PHP/peachpie/benchmark_config.json @@ -23,7 +23,7 @@ "display_name": "peachpie", "notes": "", "versus": "php", - "tags": [] + "tags": [ "broken"] } }] } diff --git a/frameworks/PHP/php/README.md b/frameworks/PHP/php/README.md index 62a8c67c23d..84db3c72477 100644 --- a/frameworks/PHP/php/README.md +++ b/frameworks/PHP/php/README.md @@ -6,22 +6,22 @@ This is the PHP portion of a [benchmarking test suite](../) comparing a variety When editing this framework, be sure to force add the files changed. Most files were added to .gitignore, as the framework touches some of them during testing. ## Infrastructure Software Versions -The tests were run with [PHP Version 7.3.*](https://www.php.net/) + OPcache +The tests were run with [PHP Version 8.*](https://www.php.net/) + OPcache ### Platforms -* [php-fpm 7.4.*](https://www.php.net/manual/en/install.fpm.php) -* [nginx unit 1.18.0](https://unit.nginx.org/) (PHP 7.4) +* [php-fpm](https://www.php.net/manual/en/install.fpm.php) + ### Webservers -* [nginx 1.17.10](https://nginx.org/) -* [h2o 2.2.6](https://h2o.examp1e.net/) +* [nginx](https://nginx.org/) +* [h2o](https://h2o.examp1e.net/) ### Databases -* [MySQL 8](https://dev.mysql.com/) -* [PostgreSQL 12](https://www.postgresql.org/) +* [MySQL 9](https://dev.mysql.com/) +* [PostgreSQL 18](https://www.postgresql.org/) ## ActiveRecord diff --git a/frameworks/PHP/php/benchmark_config.json b/frameworks/PHP/php/benchmark_config.json index fd73ea26d49..c89123406e1 100644 --- a/frameworks/PHP/php/benchmark_config.json +++ b/frameworks/PHP/php/benchmark_config.json @@ -91,30 +91,6 @@ "notes": "", "versus": "php" }, - "unit": { - "json_url": "/json.php", - "plaintext_url": "/plaintext.php", - "db_url": "/dbraw.php", - "query_url": "/dbquery.php?queries=", - "fortune_url": "/fortune.php", - "update_url": "/updateraw.php?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "framework": "PHP", - "language": "PHP", - "flavor": "PHP8.2", - "orm": "Raw", - "platform": "Unit Nginx", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "PHP Unit Nginx", - "notes": "", - "versus": "php", - "tags": [] - }, "pools": { "json_url": "/json.php", "plaintext_url": "/plaintext.php", diff --git a/frameworks/PHP/php/config.toml b/frameworks/PHP/php/config.toml index c96af5d147c..655763df023 100644 --- a/frameworks/PHP/php/config.toml +++ b/frameworks/PHP/php/config.toml @@ -111,20 +111,3 @@ orm = "Raw" platform = "FPM/FastCGI" webserver = "nginx" versus = "php" - -[unit] -urls.plaintext = "/plaintext.php" -urls.json = "/json.php" -urls.db = "/dbraw.php" -urls.query = "/dbquery.php?queries=" -urls.update = "/updateraw.php?queries=" -urls.fortune = "/fortune.php" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Unit Nginx" -webserver = "None" -versus = "php" diff --git a/frameworks/PHP/php/deploy/nginx-unit.json b/frameworks/PHP/php/deploy/nginx-unit.json deleted file mode 100644 index 51fcc77c5bb..00000000000 --- a/frameworks/PHP/php/deploy/nginx-unit.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "listeners": { - "*:8080": { - "pass": "applications/benchmark" - } - }, - - "applications": { - "benchmark": { - "type": "php", - "processes": { - "max": 224, - "spare": 168, - "idle_timeout": 20 - }, - "user": "www-data", - "group": "www-data", - "root": "/php/", - "options": { - "file": "/php/deploy/conf/php.ini" - }, - "limits": { - "requests": 10000000 - } - } - }, - "settings": { - "http": { - "server_version": false - } - } -} \ No newline at end of file diff --git a/frameworks/PHP/php/php-h2o.dockerfile b/frameworks/PHP/php/php-h2o.dockerfile index 013c6de55c0..62f874cd700 100644 --- a/frameworks/PHP/php/php-h2o.dockerfile +++ b/frameworks/PHP/php/php-h2o.dockerfile @@ -4,7 +4,7 @@ ARG H2O_PREFIX=/opt/h2o FROM "buildpack-deps:${UBUNTU_VERSION}" AS compile -ARG H2O_VERSION=3b9b6a53cac8bcc6a25fb28df81ad295fc5f9402 +ARG H2O_VERSION=ccea64b17ade832753db933658047ede9f31a380 ARG DEBIAN_FRONTEND=noninteractive ARG H2O_PREFIX @@ -20,10 +20,8 @@ RUN apt-get install \ libssl-dev \ liburing-dev \ libuv1-dev \ - libwslay-dev \ libz-dev \ make \ - ninja-build \ pkg-config \ ruby \ systemtap-sdt-dev > /dev/null && \ @@ -31,10 +29,10 @@ RUN apt-get install \ tar --strip-components=1 -xz > /dev/null && \ cmake \ -B build \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ -DCMAKE_INSTALL_PREFIX="${H2O_PREFIX}" \ -DWITH_MRUBY=on \ - -G Ninja \ -S . > /dev/null && \ cmake --build build -j > /dev/null && \ cmake --install build > /dev/null diff --git a/frameworks/PHP/php/php-unit.dockerfile b/frameworks/PHP/php/php-unit.dockerfile deleted file mode 100644 index 04a0539eca1..00000000000 --- a/frameworks/PHP/php/php-unit.dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM unit:php8.4 - -RUN docker-php-ext-install pdo_mysql opcache > /dev/null - -WORKDIR /php -COPY --link . . - -RUN if [ $(nproc) = 2 ]; then sed -i "s|\"spare\": 168,|\"spare\": 64,|g" /php/deploy/nginx-unit.json ; fi; - -#RUN more /php/deploy/nginx-unit.json - -RUN unitd && \ - curl -X PUT --data-binary @/php/deploy/nginx-unit.json --unix-socket \ - /var/run/control.unit.sock http://localhost/config - -ENTRYPOINT [ ] - -EXPOSE 8080 - -CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] diff --git a/frameworks/PHP/simps/README.md b/frameworks/PHP/simps/README.md index 4ca3f0dc330..8098e663f82 100755 --- a/frameworks/PHP/simps/README.md +++ b/frameworks/PHP/simps/README.md @@ -1,5 +1,5 @@

- + Simps

@@ -17,16 +17,16 @@ 🚀 A simple, lightweight and high-performance PHP coroutine framework. -[Home Page](https://simps.io) -[Documentation](https://doc.simps.io) +[Documentation](https://doc.simps.io/#/en/) +[Source Code](https://github.com/simple-swoole/simps) ## Important Libraries The tests were run with: -* [PHP7](https://www.php.net) -* [Swoole4](https://www.swoole.com) -* [Simps](https://simps.io) +* [PHP](https://www.php.net) +* [Swoole](https://www.swoole.com) +* [Simps](https://doc.simps.io/#/en/) ## Test URLs diff --git a/frameworks/PHP/simps/benchmark_config.json b/frameworks/PHP/simps/benchmark_config.json index 78db8849ece..ed656625e77 100755 --- a/frameworks/PHP/simps/benchmark_config.json +++ b/frameworks/PHP/simps/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "simps", + "maintainers": ["sy-records"], "tests": [ { "default": { diff --git a/frameworks/PHP/simps/config/servers.php b/frameworks/PHP/simps/config/servers.php index 9f8b13a9d9c..d2292686045 100644 --- a/frameworks/PHP/simps/config/servers.php +++ b/frameworks/PHP/simps/config/servers.php @@ -20,6 +20,7 @@ 'settings' => [ 'worker_num' => swoole_cpu_num(), 'only_simple_http' => true, + 'http_compression' => false, ], ], ]; \ No newline at end of file diff --git a/frameworks/PHP/simps/simps-micro.dockerfile b/frameworks/PHP/simps/simps-micro.dockerfile index 4e5b9ffd075..a79ab8e419e 100644 --- a/frameworks/PHP/simps/simps-micro.dockerfile +++ b/frameworks/PHP/simps/simps-micro.dockerfile @@ -1,13 +1,11 @@ -FROM phpswoole/swoole:5.1.3-php8.3 - -RUN docker-php-ext-install pcntl opcache curl > /dev/null +FROM phpswoole/swoole:php8.5 WORKDIR /simps COPY --link . . COPY --link php.ini /usr/local/etc/php/ -RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null +RUN composer install --no-dev --classmap-authoritative --quiet RUN composer dumpautoload -o EXPOSE 8080 diff --git a/frameworks/PHP/simps/simps.dockerfile b/frameworks/PHP/simps/simps.dockerfile index 4e5b9ffd075..a79ab8e419e 100644 --- a/frameworks/PHP/simps/simps.dockerfile +++ b/frameworks/PHP/simps/simps.dockerfile @@ -1,13 +1,11 @@ -FROM phpswoole/swoole:5.1.3-php8.3 - -RUN docker-php-ext-install pcntl opcache curl > /dev/null +FROM phpswoole/swoole:php8.5 WORKDIR /simps COPY --link . . COPY --link php.ini /usr/local/etc/php/ -RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null +RUN composer install --no-dev --classmap-authoritative --quiet RUN composer dumpautoload -o EXPOSE 8080 diff --git a/frameworks/PHP/swoole/10-opcache.ini b/frameworks/PHP/swoole/10-opcache.ini deleted file mode 100644 index bc77a43761e..00000000000 --- a/frameworks/PHP/swoole/10-opcache.ini +++ /dev/null @@ -1,10 +0,0 @@ -zend_extension=opcache.so -opcache.enable=1 -opcache.enable_cli=1 -opcache.validate_timestamps=0 -opcache.save_comments=0 -opcache.enable_file_override=1 -opcache.huge_code_pages=1 -opcache.jit_buffer_size=128M -mysqlnd.collect_statistics = Off -opcache.jit=tracing diff --git a/frameworks/PHP/swoole/benchmark_config.json b/frameworks/PHP/swoole/benchmark_config.json index 42b506b2ef7..26914688a85 100644 --- a/frameworks/PHP/swoole/benchmark_config.json +++ b/frameworks/PHP/swoole/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "swoole", + "maintainers": ["NathanFreeman"], "tests": [{ "default": { "dockerfile": "swoole-sync-mysql.dockerfile", diff --git a/frameworks/PHP/swoole/override.ini b/frameworks/PHP/swoole/override.ini new file mode 100644 index 00000000000..e67d216bf2a --- /dev/null +++ b/frameworks/PHP/swoole/override.ini @@ -0,0 +1,12 @@ +zend_extension=opcache.so +opcache.enable=1 +opcache.enable_cli=1 +opcache.validate_timestamps=0 +opcache.save_comments=0 +opcache.enable_file_override=1 +opcache.huge_code_pages=1 +opcache.jit_buffer_size=128M +mysqlnd.collect_statistics = Off +opcache.jit=tracing + +memory_limit=1024M \ No newline at end of file diff --git a/frameworks/PHP/swoole/database.php b/frameworks/PHP/swoole/src/database.php similarity index 100% rename from frameworks/PHP/swoole/database.php rename to frameworks/PHP/swoole/src/database.php diff --git a/frameworks/PHP/swoole/swoole-server.php b/frameworks/PHP/swoole/src/swoole-server.php similarity index 100% rename from frameworks/PHP/swoole/swoole-server.php rename to frameworks/PHP/swoole/src/swoole-server.php diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index 632481846ba..660888ec014 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.04 +FROM phpswoole/swoole:php8.5 ENV ENABLE_COROUTINE 1 ENV CPU_MULTIPLES 1 @@ -6,22 +6,13 @@ ENV DATABASE_DRIVER mysql ARG DEBIAN_FRONTEND=noninteractive -RUN apt update -yqq > /dev/null \ - && apt install -yqq software-properties-common > /dev/null \ - && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ - && apt update -yqq > /dev/null \ - && apt install git libbrotli-dev php8.4-cli php8.4-pdo-mysql php8.4-dev -y > /dev/null \ - && pecl install swoole > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.4/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.4/cli/php.ini \ - && php --ri swoole +RUN php --ri swoole WORKDIR /swoole +COPY src . -ADD ./swoole-server.php /swoole -ADD ./database.php /swoole - -COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY override.ini /usr/local/etc/php/conf.d/ +#RUN php -i EXPOSE 8080 -CMD php /swoole/swoole-server.php +CMD ["php", "/swoole/swoole-server.php"] diff --git a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile index ed6bdd36f5d..4d2b7ce98d1 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.04 +FROM phpswoole/swoole:php8.5 ENV ENABLE_COROUTINE 1 ENV CPU_MULTIPLES 1 @@ -6,22 +6,13 @@ ENV DATABASE_DRIVER pgsql ARG DEBIAN_FRONTEND=noninteractive -RUN apt update -yqq > /dev/null \ - && apt install -yqq software-properties-common > /dev/null \ - && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ - && apt update -yqq > /dev/null \ - && apt install git libbrotli-dev php8.4-cli php8.4-pdo-pgsql php8.4-dev libpq-dev -y > /dev/null \ - && pecl install -D 'enable-swoole-pgsql="yes"' swoole > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.4/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.4/cli/php.ini \ - && php --ri swoole +RUN php --ri swoole WORKDIR /swoole +COPY src . -ADD ./swoole-server.php /swoole -ADD ./database.php /swoole - -COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY override.ini /usr/local/etc/php/conf.d/ +#RUN php -i EXPOSE 8080 -CMD php /swoole/swoole-server.php +CMD ["php", "/swoole/swoole-server.php"] diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index fa92ac2d197..4a7c3bdca0c 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -1,27 +1,18 @@ -FROM ubuntu:24.04 +FROM phpswoole/swoole:php8.5 ENV ENABLE_COROUTINE 0 -ENV CPU_MULTIPLES 1 +ENV CPU_MULTIPLES 4 ENV DATABASE_DRIVER mysql ARG DEBIAN_FRONTEND=noninteractive -RUN apt update -yqq > /dev/null \ - && apt install -yqq software-properties-common > /dev/null \ - && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ - && apt update -yqq > /dev/null \ - && apt install git libbrotli-dev php8.4-cli php8.4-pdo-mysql php8.4-dev -y > /dev/null \ - && pecl install swoole > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.4/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.4/cli/php.ini \ - && php --ri swoole +RUN php --ri swoole WORKDIR /swoole +COPY src . -ADD ./swoole-server.php /swoole -ADD ./database.php /swoole - -COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY override.ini /usr/local/etc/php/conf.d/ +#RUN php -i EXPOSE 8080 -CMD php /swoole/swoole-server.php +CMD ["php", "/swoole/swoole-server.php"] diff --git a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile index f27393f8ddd..14022cfbe8f 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.04 +FROM phpswoole/swoole:php8.5 ENV ENABLE_COROUTINE 0 ENV CPU_MULTIPLES 4 @@ -6,22 +6,13 @@ ENV DATABASE_DRIVER pgsql ARG DEBIAN_FRONTEND=noninteractive -RUN apt update -yqq > /dev/null \ - && apt install -yqq software-properties-common > /dev/null \ - && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \ - && apt update -yqq > /dev/null \ - && apt install git libbrotli-dev php8.4-cli php8.4-pdo-pgsql php8.4-dev libpq-dev -y > /dev/null \ - && pecl install swoole > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.4/cli/conf.d/50-swoole.ini \ - && echo "memory_limit=1024M" >> /etc/php/8.4/cli/php.ini \ - && php --ri swoole +RUN php --ri swoole WORKDIR /swoole +COPY src . -ADD ./swoole-server.php /swoole -ADD ./database.php /swoole - -COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini +COPY override.ini /usr/local/etc/php/conf.d/ +#RUN php -i EXPOSE 8080 -CMD php /swoole/swoole-server.php +CMD ["php", "/swoole/swoole-server.php"] diff --git a/frameworks/PHP/symfony/composer.json b/frameworks/PHP/symfony/composer.json index 9061d99d608..82a8674ad97 100644 --- a/frameworks/PHP/symfony/composer.json +++ b/frameworks/PHP/symfony/composer.json @@ -2,17 +2,17 @@ "type": "project", "license": "proprietary", "require": { - "php": ">=8.2", + "php": ">=8.4", "ext-ctype": "*", "ext-iconv": "*", "ext-mbstring": "*", - "symfony/console": "^7", - "symfony/dotenv": "^7", + "symfony/console": "^8", + "symfony/dotenv": "^8", "symfony/flex": "^2", - "symfony/framework-bundle": "^7", + "symfony/framework-bundle": "^8", "symfony/orm-pack": "^2", - "symfony/twig-bundle": "^7", - "symfony/yaml": "^7", + "symfony/twig-bundle": "^8", + "symfony/yaml": "^8", "joanhey/adapterman": "^0.7" }, "minimum-stability": "dev", @@ -49,7 +49,8 @@ "symfony/polyfill-php81": "*", "symfony/polyfill-php82": "*", "symfony/polyfill-php83": "*", - "symfony/polyfill-php84": "*" + "symfony/polyfill-php84": "*", + "symfony/polyfill-php85": "*" }, "scripts": { "auto-scripts": { diff --git a/frameworks/PHP/symfony/deploy/react/php.ini b/frameworks/PHP/symfony/deploy/react/php.ini new file mode 100644 index 00000000000..54182323396 --- /dev/null +++ b/frameworks/PHP/symfony/deploy/react/php.ini @@ -0,0 +1,22 @@ +display_errors=On +display_startup_errors=On +short_open_tag=Off + +session.gc_probability=0 +session.gc_divisor=1000 + +swoole.display_errors=On + +memory_limit=512M + +realpath_cache_size=4096K +realpath_cache_ttl=600 + +opcache.enable_cli=1 +opcache.validate_timestamps=0 +opcache.memory_consumption=256 +opcache.max_accelerated_files=20000 +opcache.preload_user=www-data + +opcache.jit_buffer_size = 128M +opcache.jit = tracing diff --git a/frameworks/PHP/symfony/deploy/swoole/php.ini b/frameworks/PHP/symfony/deploy/swoole/php.ini index 54182323396..c5bbb8cb79d 100644 --- a/frameworks/PHP/symfony/deploy/swoole/php.ini +++ b/frameworks/PHP/symfony/deploy/swoole/php.ini @@ -18,5 +18,5 @@ opcache.memory_consumption=256 opcache.max_accelerated_files=20000 opcache.preload_user=www-data -opcache.jit_buffer_size = 128M -opcache.jit = tracing +#opcache.jit_buffer_size = 128M +#opcache.jit = tracing diff --git a/frameworks/PHP/symfony/src/Kernel.php b/frameworks/PHP/symfony/src/Kernel.php index dc42c56e114..59e1790db40 100644 --- a/frameworks/PHP/symfony/src/Kernel.php +++ b/frameworks/PHP/symfony/src/Kernel.php @@ -37,7 +37,7 @@ protected function configureRoutes(RoutingConfigurator $routes): void $routes->import('../config/{routes}.yaml'); } - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { if ($this->environment !== 'swoole') { return; diff --git a/frameworks/PHP/symfony/symfony-franken.dockerfile b/frameworks/PHP/symfony/symfony-franken.dockerfile index e20064e6a95..4af6eaf62e1 100644 --- a/frameworks/PHP/symfony/symfony-franken.dockerfile +++ b/frameworks/PHP/symfony/symfony-franken.dockerfile @@ -5,7 +5,7 @@ RUN install-php-extensions \ pdo_pgsql \ zip > /dev/null -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer COPY --link deploy/Caddyfile /etc/frankenphp/Caddyfile COPY --link deploy/conf/php.ini /usr/local/etc/php/ diff --git a/frameworks/PHP/symfony/symfony-mysql.dockerfile b/frameworks/PHP/symfony/symfony-mysql.dockerfile index 6fa2403d108..7d5b10f2c13 100644 --- a/frameworks/PHP/symfony/symfony-mysql.dockerfile +++ b/frameworks/PHP/symfony/symfony-mysql.dockerfile @@ -3,14 +3,18 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ - apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null && \ + apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq nginx git unzip curl \ php8.5-cli php8.5-fpm php8.5-mysql \ php8.5-mbstring php8.5-xml php8.5-curl > /dev/null -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +# Use Jemalloc for optimize +RUN apt install libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /symfony diff --git a/frameworks/PHP/symfony/symfony-raw.dockerfile b/frameworks/PHP/symfony/symfony-raw.dockerfile index 130fe781d15..0fbf4754002 100644 --- a/frameworks/PHP/symfony/symfony-raw.dockerfile +++ b/frameworks/PHP/symfony/symfony-raw.dockerfile @@ -3,14 +3,18 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ - apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null && \ + apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq nginx git unzip curl \ php8.5-cli php8.5-fpm php8.5-pgsql \ php8.5-mbstring php8.5-xml php8.5-curl > /dev/null -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +# Use Jemalloc for optimize +RUN apt install libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer COPY --link deploy/conf/* /etc/php/8.5/fpm/ WORKDIR /symfony diff --git a/frameworks/PHP/symfony/symfony-react.dockerfile b/frameworks/PHP/symfony/symfony-react.dockerfile index 3b57b331e76..b72ebf0cd6f 100644 --- a/frameworks/PHP/symfony/symfony-react.dockerfile +++ b/frameworks/PHP/symfony/symfony-react.dockerfile @@ -4,7 +4,7 @@ RUN apt-get update -yqq && \ apt-get install -yqq libpq-dev libicu-dev git > /dev/null && \ docker-php-ext-install pdo_pgsql intl pcntl > /dev/null -COPY --link deploy/swoole/php.ini /usr/local/etc/php/ +COPY --link deploy/react/php.ini /usr/local/etc/php/ WORKDIR /symfony COPY --link . . @@ -19,8 +19,11 @@ RUN docker-php-ext-enable uv # && pecl install event-3.1.4 > /dev/null # RUN docker-php-ext-enable event +# Use Jemalloc for optimize +RUN apt install libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer #ENV APP_DEBUG 1 ENV APP_ENV prod @@ -28,6 +31,9 @@ ENV APP_ENV prod #ENV APP_RUNTIME "Runtime\React\Runtime" #RUN composer require runtime/react --update-no-dev --no-scripts --quiet +#fix to run Symfony 7 with React Zolex bundle +RUN sed -i "s|\\^8|\\^7|g" /symfony/composer.json + ENV APP_RUNTIME "Zolex\ReactPhpBundle\Runtime\ReactPhpRuntime" ENV REACT_HOST "0.0.0.0" RUN composer require zolex/reactphp-bundle --update-no-dev --no-scripts --quiet diff --git a/frameworks/PHP/symfony/symfony-roadrunner.dockerfile b/frameworks/PHP/symfony/symfony-roadrunner.dockerfile index 7fae6298c8b..e265416084f 100644 --- a/frameworks/PHP/symfony/symfony-roadrunner.dockerfile +++ b/frameworks/PHP/symfony/symfony-roadrunner.dockerfile @@ -2,7 +2,7 @@ FROM php:8.5-cli COPY --from=ghcr.io/roadrunner-server/roadrunner:2025.1 --link /usr/bin/rr /usr/local/bin/rr COPY --from=mlocati/php-extension-installer --link /usr/bin/install-php-extensions /usr/local/bin/ -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer RUN install-php-extensions \ intl \ diff --git a/frameworks/PHP/symfony/symfony-swoole.dockerfile b/frameworks/PHP/symfony/symfony-swoole.dockerfile index c9d32159b13..89ab1119740 100644 --- a/frameworks/PHP/symfony/symfony-swoole.dockerfile +++ b/frameworks/PHP/symfony/symfony-swoole.dockerfile @@ -1,8 +1,8 @@ -FROM phpswoole/swoole:php8.4 +FROM phpswoole/swoole:php8.5 RUN apt-get update -yqq && \ apt-get install -yqq libpq-dev libicu-dev > /dev/null && \ - docker-php-ext-install pdo_pgsql opcache intl > /dev/null + docker-php-ext-install pdo_pgsql intl > /dev/null RUN pecl install apcu > /dev/null && \ docker-php-ext-enable apcu diff --git a/frameworks/PHP/symfony/symfony-workerman.dockerfile b/frameworks/PHP/symfony/symfony-workerman.dockerfile index fe5d5ce9ba6..07b996d36e5 100644 --- a/frameworks/PHP/symfony/symfony-workerman.dockerfile +++ b/frameworks/PHP/symfony/symfony-workerman.dockerfile @@ -3,13 +3,17 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ - apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null && \ + apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq unzip \ php8.5-cli php8.5-pgsql php8.5-mbstring php8.5-xml php8.5-curl > /dev/null -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +# Use Jemalloc for optimize +RUN apt install libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.5-dev libevent-dev > /dev/null && \ pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.5/cli/conf.d/event.ini diff --git a/frameworks/PHP/symfony/symfony.dockerfile b/frameworks/PHP/symfony/symfony.dockerfile index 6d685dfb987..151f6241c52 100644 --- a/frameworks/PHP/symfony/symfony.dockerfile +++ b/frameworks/PHP/symfony/symfony.dockerfile @@ -3,14 +3,18 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ - apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null +RUN LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null && \ + apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq nginx git unzip curl \ php8.5-bcmath php8.5-cli php8.5-fpm php8.5-pgsql \ php8.5-mbstring php8.5-xml php8.5-curl php8.5-intl > /dev/null -COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer +# Use Jemalloc for optimize +RUN apt install libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY --from=composer/composer:2-bin --link /composer /usr/local/bin/composer COPY --link deploy/conf/* /etc/php/8.5/fpm/ diff --git a/frameworks/PHP/ubiquity/benchmark_config.json b/frameworks/PHP/ubiquity/benchmark_config.json index 70548c4f91e..47fa6db73a0 100644 --- a/frameworks/PHP/ubiquity/benchmark_config.json +++ b/frameworks/PHP/ubiquity/benchmark_config.json @@ -177,7 +177,8 @@ "database_os": "Linux", "display_name": "ubiquity-workerman-mongo", "notes": "", - "versus": "php" + "versus": "php", + "tags": ["broken"] }, "workerman-raw": { "json_url": "/Json_", diff --git a/frameworks/Perl/dancer/dancer.dockerfile b/frameworks/Perl/dancer/dancer.dockerfile index 0094ff8fca8..e18e141cb0f 100644 --- a/frameworks/Perl/dancer/dancer.dockerfile +++ b/frameworks/Perl/dancer/dancer.dockerfile @@ -1,9 +1,9 @@ -FROM perl:5.40 +FROM perl:5.42 RUN apt-get update -yqq && apt-get install -yqq nginx -ADD ./ /dancer WORKDIR /dancer +COPY . . RUN cpanm --notest --no-man-page \ JSON IO::Socket::IP IO::Socket::SSL \ diff --git a/frameworks/Perl/feersum/README.md b/frameworks/Perl/feersum/README.md index a620bf8e9de..971105bb6f8 100644 --- a/frameworks/Perl/feersum/README.md +++ b/frameworks/Perl/feersum/README.md @@ -5,7 +5,7 @@ # Requirements -* Perl 5.40) +* Perl 5.42) * [JSON::XS](https://metacpan.org/dist/JSON-XS) * [DBI](https://metacpan.org/dist/DBI) * [Text::Xslate](https://metacpan.org/dist/Text-Xslate) diff --git a/frameworks/Perl/feersum/app.pl b/frameworks/Perl/feersum/app.pl index f826a2791a0..0032d011b73 100644 --- a/frameworks/Perl/feersum/app.pl +++ b/frameworks/Perl/feersum/app.pl @@ -1,4 +1,4 @@ -use v5.40; +use v5.42; use warnings; use Feersum::Runner; use EV; use AnyEvent; diff --git a/frameworks/Perl/feersum/benchmark_config.json b/frameworks/Perl/feersum/benchmark_config.json index 383b356f644..ebdbc8a5b94 100644 --- a/frameworks/Perl/feersum/benchmark_config.json +++ b/frameworks/Perl/feersum/benchmark_config.json @@ -23,7 +23,6 @@ "platform": "None", "webserver": "feersum", "os": "Linux", - "database_os": "Linux", "display_name": "feersum", "notes": "" }, @@ -46,9 +45,9 @@ "platform": "None", "webserver": "feersum", "os": "Linux", - "database_os": "Linux", "display_name": "feersum", - "notes": "" + "notes": "", + "tags": ["broken"] } }] } diff --git a/frameworks/Perl/feersum/cpanfile b/frameworks/Perl/feersum/cpanfile index 02a462a22e4..1303b7b0d26 100644 --- a/frameworks/Perl/feersum/cpanfile +++ b/frameworks/Perl/feersum/cpanfile @@ -1,8 +1,9 @@ requires 'Feersum', '== 1.505'; requires 'JSON::XS', '== 4.03'; -requires 'DBD::MariaDB', '== 1.23'; +requires 'DBD::MariaDB', '== 1.24'; requires 'DBD::Pg', '== 3.18.0'; requires 'AnyEvent', '== 7.17'; requires 'Async::Interrupt', '== 1.26'; requires 'Text::Xslate', '== v3.5.9'; requires 'LMDB_File', '== 0.14'; +#requires 'DBD::mysql', '== 5.013'; diff --git a/frameworks/Perl/feersum/cpanfile_alt b/frameworks/Perl/feersum/cpanfile_alt deleted file mode 100644 index 7b26f606c2d..00000000000 --- a/frameworks/Perl/feersum/cpanfile_alt +++ /dev/null @@ -1 +0,0 @@ -requires 'DBD::mysql', '== 5.009'; diff --git a/frameworks/Perl/feersum/feersum.dockerfile b/frameworks/Perl/feersum/feersum.dockerfile index ed8865deb4f..6f9d7c09bea 100644 --- a/frameworks/Perl/feersum/feersum.dockerfile +++ b/frameworks/Perl/feersum/feersum.dockerfile @@ -1,28 +1,17 @@ -from perl:5.40-slim -run apt-get update -run apt-get install -y --no-install-recommends --no-install-suggests catatonit libmariadb-dev libpq-dev libev-dev liblmdb-dev build-essential curl gnupg -run curl -fsSL https://raw.githubusercontent.com/skaji/cpm/main/cpm | perl - install -g App::cpm -workdir /app -add cpanfile . -run cpm install -g +FROM perl:5.42 +RUN apt-get update +RUN apt-get install -y --no-install-recommends --no-install-suggests catatonit default-libmysqlclient-dev libmariadb-dev libpq-dev libev-dev liblmdb-dev build-essential curl gnupg +RUN curl -fsSL https://raw.githubusercontent.com/skaji/cpm/main/cpm | perl - install -g App::cpm +WORKDIR /app +COPY cpanfile . +RUN cpm install -g --show-build-log-on-failure -run curl https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 -o /etc/apt/trusted.gpg.d/mysql2023 -run gpg --dearmor /etc/apt/trusted.gpg.d/mysql2023 -run rm /etc/apt/trusted.gpg.d/mysql2023 -run echo 'deb http://repo.mysql.com/apt/debian bookworm mysql-innovation' > /etc/apt/sources.list.d/mysql.list -run apt-get update -run apt-get install -y --no-install-recommends --no-install-suggests libmysqlclient-dev -add cpanfile_alt . -run cpm install -g --cpanfile=cpanfile_alt +COPY app.pl . +EXPOSE 8080 -run apt-get clean -run rm -rf $HOME/.perl-cpm -add app.pl . -expose 8080 +ARG TFB_TEST_DATABASE +ENV db=$TFB_TEST_DATABASE -arg TFB_TEST_DATABASE -env db=$TFB_TEST_DATABASE +STOPSIGNAL SIGKILL -stopsignal SIGKILL - -cmd perl app.pl +CMD perl app.pl diff --git a/frameworks/Perl/kelp/kelp.dockerfile b/frameworks/Perl/kelp/kelp.dockerfile index b8bd3453317..fef9a0a88e3 100644 --- a/frameworks/Perl/kelp/kelp.dockerfile +++ b/frameworks/Perl/kelp/kelp.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.40 +FROM perl:5.42 ARG TFB_TEST_NAME ARG TFB_TEST_DATABASE diff --git a/frameworks/Perl/mojolicious/app.pl b/frameworks/Perl/mojolicious/app.pl index 465c2c7381c..c50ee18b99b 100644 --- a/frameworks/Perl/mojolicious/app.pl +++ b/frameworks/Perl/mojolicious/app.pl @@ -1,5 +1,4 @@ -use v5.36; -use Mojolicious::Lite; +use Mojolicious::Lite -signatures; use Mojo::Pg; use Mojo::Promise; diff --git a/frameworks/Perl/mojolicious/cpanfile b/frameworks/Perl/mojolicious/cpanfile index 68299a759ce..558bad2a951 100644 --- a/frameworks/Perl/mojolicious/cpanfile +++ b/frameworks/Perl/mojolicious/cpanfile @@ -1,8 +1,8 @@ -requires 'Mojolicious', '7.84'; -requires 'Mojo::Pg', '4.08'; -requires 'Cpanel::JSON::XS', '4.38'; -requires 'EV', '4.22'; +requires 'Mojolicious', '9.42'; +requires 'Mojo::Pg'; +requires 'Cpanel::JSON::XS'; +requires 'EV'; -recommends 'IO::Socket::IP', '0.36'; +recommends 'IO::Socket::IP'; recommends 'IO::Socket::SSL'; diff --git a/frameworks/Perl/mojolicious/cpanfile.snapshot b/frameworks/Perl/mojolicious/cpanfile.snapshot deleted file mode 100644 index c3f7c9e074b..00000000000 --- a/frameworks/Perl/mojolicious/cpanfile.snapshot +++ /dev/null @@ -1,464 +0,0 @@ -# carton snapshot format: version 1.0 -DISTRIBUTIONS - Canary-Stability-2013 - pathname: M/ML/MLEHMANN/Canary-Stability-2013.tar.gz - provides: - Canary::Stability 2013 - requirements: - ExtUtils::MakeMaker 0 - Class-Method-Modifiers-2.15 - pathname: E/ET/ETHER/Class-Method-Modifiers-2.15.tar.gz - provides: - Class::Method::Modifiers 2.15 - requirements: - B 0 - Carp 0 - Exporter 0 - ExtUtils::MakeMaker 0 - base 0 - perl 5.006 - strict 0 - warnings 0 - Clone-Choose-0.010 - pathname: H/HE/HERMES/Clone-Choose-0.010.tar.gz - provides: - Clone::Choose 0.010 - requirements: - ExtUtils::MakeMaker 0 - Storable 0 - perl 5.008001 - Cpanel-JSON-XS-4.38 - pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.38.tar.gz - provides: - Cpanel::JSON::XS 4.38 - Cpanel::JSON::XS::Type undef - requirements: - Carp 0 - Config 0 - Encode 1.9801 - Exporter 0 - ExtUtils::MakeMaker 0 - Pod::Text 2.08 - XSLoader 0 - overload 0 - strict 0 - warnings 0 - DBD-Pg-3.18.0 - pathname: T/TU/TURNSTEP/DBD-Pg-3.18.0.tar.gz - provides: - Bundle::DBD::Pg v3.18.0 - DBD::Pg v3.18.0 - requirements: - DBI 1.614 - ExtUtils::MakeMaker 6.58 - File::Temp 0 - Test::More 0.88 - Time::HiRes 0 - version 0 - DBI-1.643 - pathname: T/TI/TIMB/DBI-1.643.tar.gz - provides: - Bundle::DBI 12.008696 - DBD::DBM 0.08 - DBD::DBM::Statement 0.08 - DBD::DBM::Table 0.08 - DBD::DBM::db 0.08 - DBD::DBM::dr 0.08 - DBD::DBM::st 0.08 - DBD::ExampleP 12.014311 - DBD::ExampleP::db 12.014311 - DBD::ExampleP::dr 12.014311 - DBD::ExampleP::st 12.014311 - DBD::File 0.44 - DBD::File::DataSource::File 0.44 - DBD::File::DataSource::Stream 0.44 - DBD::File::Statement 0.44 - DBD::File::Table 0.44 - DBD::File::TableSource::FileSystem 0.44 - DBD::File::db 0.44 - DBD::File::dr 0.44 - DBD::File::st 0.44 - DBD::Gofer 0.015327 - DBD::Gofer::Policy::Base 0.010088 - DBD::Gofer::Policy::classic 0.010088 - DBD::Gofer::Policy::pedantic 0.010088 - DBD::Gofer::Policy::rush 0.010088 - DBD::Gofer::Transport::Base 0.014121 - DBD::Gofer::Transport::corostream undef - DBD::Gofer::Transport::null 0.010088 - DBD::Gofer::Transport::pipeone 0.010088 - DBD::Gofer::Transport::stream 0.014599 - DBD::Gofer::db 0.015327 - DBD::Gofer::dr 0.015327 - DBD::Gofer::st 0.015327 - DBD::Mem 0.001 - DBD::Mem::DataSource 0.001 - DBD::Mem::Statement 0.001 - DBD::Mem::Table 0.001 - DBD::Mem::db 0.001 - DBD::Mem::dr 0.001 - DBD::Mem::st 0.001 - DBD::NullP 12.014715 - DBD::NullP::db 12.014715 - DBD::NullP::dr 12.014715 - DBD::NullP::st 12.014715 - DBD::Proxy 0.2004 - DBD::Proxy::RPC::PlClient 0.2004 - DBD::Proxy::db 0.2004 - DBD::Proxy::dr 0.2004 - DBD::Proxy::st 0.2004 - DBD::Sponge 12.010003 - DBD::Sponge::db 12.010003 - DBD::Sponge::dr 12.010003 - DBD::Sponge::st 12.010003 - DBDI 12.015129 - DBI 1.643 - DBI::Const::GetInfo::ANSI 2.008697 - DBI::Const::GetInfo::ODBC 2.011374 - DBI::Const::GetInfoReturn 2.008697 - DBI::Const::GetInfoType 2.008697 - DBI::DBD 12.015129 - DBI::DBD::Metadata 2.014214 - DBI::DBD::SqlEngine 0.06 - DBI::DBD::SqlEngine::DataSource 0.06 - DBI::DBD::SqlEngine::Statement 0.06 - DBI::DBD::SqlEngine::Table 0.06 - DBI::DBD::SqlEngine::TableSource 0.06 - DBI::DBD::SqlEngine::TieMeta 0.06 - DBI::DBD::SqlEngine::TieTables 0.06 - DBI::DBD::SqlEngine::db 0.06 - DBI::DBD::SqlEngine::dr 0.06 - DBI::DBD::SqlEngine::st 0.06 - DBI::Gofer::Execute 0.014283 - DBI::Gofer::Request 0.012537 - DBI::Gofer::Response 0.011566 - DBI::Gofer::Serializer::Base 0.009950 - DBI::Gofer::Serializer::DataDumper 0.009950 - DBI::Gofer::Serializer::Storable 0.015586 - DBI::Gofer::Transport::Base 0.012537 - DBI::Gofer::Transport::pipeone 0.012537 - DBI::Gofer::Transport::stream 0.012537 - DBI::Profile 2.015065 - DBI::ProfileData 2.010008 - DBI::ProfileDumper 2.015325 - DBI::ProfileDumper::Apache 2.014121 - DBI::ProfileSubs 0.009396 - DBI::ProxyServer 0.3005 - DBI::ProxyServer::db 0.3005 - DBI::ProxyServer::dr 0.3005 - DBI::ProxyServer::st 0.3005 - DBI::SQL::Nano 1.015544 - DBI::SQL::Nano::Statement_ 1.015544 - DBI::SQL::Nano::Table_ 1.015544 - DBI::Util::CacheMemory 0.010315 - DBI::Util::_accessor 0.009479 - DBI::common 1.643 - requirements: - ExtUtils::MakeMaker 6.48 - Test::Simple 0.90 - perl 5.008001 - EV-4.34 - pathname: M/ML/MLEHMANN/EV-4.34.tar.gz - provides: - EV 4.34 - EV::MakeMaker undef - requirements: - Canary::Stability 0 - ExtUtils::MakeMaker 6.52 - common::sense 0 - Hash-Merge-0.302 - pathname: H/HE/HERMES/Hash-Merge-0.302.tar.gz - provides: - Hash::Merge 0.302 - requirements: - Clone::Choose 0.008 - ExtUtils::MakeMaker 6.64 - Scalar::Util 0 - perl 5.008001 - MRO-Compat-0.15 - pathname: H/HA/HAARG/MRO-Compat-0.15.tar.gz - provides: - MRO::Compat 0.15 - requirements: - ExtUtils::MakeMaker 0 - perl 5.006 - Mojo-Pg-4.27 - pathname: S/SR/SRI/Mojo-Pg-4.27.tar.gz - provides: - Mojo::Pg 4.27 - Mojo::Pg::Database undef - Mojo::Pg::Migrations undef - Mojo::Pg::PubSub undef - Mojo::Pg::Results undef - Mojo::Pg::Transaction undef - requirements: - DBD::Pg 3.007004 - ExtUtils::MakeMaker 0 - Mojolicious 8.50 - SQL::Abstract::Pg 1.0 - perl 5.016 - Mojolicious-9.37 - pathname: S/SR/SRI/Mojolicious-9.37.tar.gz - provides: - Mojo undef - Mojo::Asset undef - Mojo::Asset::File undef - Mojo::Asset::Memory undef - Mojo::Base undef - Mojo::BaseUtil undef - Mojo::ByteStream undef - Mojo::Cache undef - Mojo::Collection undef - Mojo::Content undef - Mojo::Content::MultiPart undef - Mojo::Content::Single undef - Mojo::Cookie undef - Mojo::Cookie::Request undef - Mojo::Cookie::Response undef - Mojo::DOM undef - Mojo::DOM::CSS undef - Mojo::DOM::HTML undef - Mojo::Date undef - Mojo::DynamicMethods undef - Mojo::EventEmitter undef - Mojo::Exception undef - Mojo::File undef - Mojo::Headers undef - Mojo::HelloWorld undef - Mojo::Home undef - Mojo::IOLoop undef - Mojo::IOLoop::Client undef - Mojo::IOLoop::Server undef - Mojo::IOLoop::Stream undef - Mojo::IOLoop::Subprocess undef - Mojo::IOLoop::TLS undef - Mojo::JSON undef - Mojo::JSON::Pointer undef - Mojo::Loader undef - Mojo::Log undef - Mojo::Message undef - Mojo::Message::Request undef - Mojo::Message::Response undef - Mojo::Parameters undef - Mojo::Path undef - Mojo::Promise undef - Mojo::Reactor undef - Mojo::Reactor::EV undef - Mojo::Reactor::Poll undef - Mojo::Server undef - Mojo::Server::CGI undef - Mojo::Server::Daemon undef - Mojo::Server::Hypnotoad undef - Mojo::Server::Morbo undef - Mojo::Server::Morbo::Backend undef - Mojo::Server::Morbo::Backend::Poll undef - Mojo::Server::PSGI undef - Mojo::Server::Prefork undef - Mojo::Template undef - Mojo::Transaction undef - Mojo::Transaction::HTTP undef - Mojo::Transaction::WebSocket undef - Mojo::URL undef - Mojo::Upload undef - Mojo::UserAgent undef - Mojo::UserAgent::CookieJar undef - Mojo::UserAgent::Proxy undef - Mojo::UserAgent::Server undef - Mojo::UserAgent::Transactor undef - Mojo::Util undef - Mojo::WebSocket undef - Mojolicious 9.37 - Mojolicious::Command undef - Mojolicious::Command::Author::cpanify undef - Mojolicious::Command::Author::generate undef - Mojolicious::Command::Author::generate::app undef - Mojolicious::Command::Author::generate::dockerfile undef - Mojolicious::Command::Author::generate::lite_app undef - Mojolicious::Command::Author::generate::makefile undef - Mojolicious::Command::Author::generate::plugin undef - Mojolicious::Command::Author::inflate undef - Mojolicious::Command::cgi undef - Mojolicious::Command::daemon undef - Mojolicious::Command::eval undef - Mojolicious::Command::get undef - Mojolicious::Command::prefork undef - Mojolicious::Command::psgi undef - Mojolicious::Command::routes undef - Mojolicious::Command::version undef - Mojolicious::Commands undef - Mojolicious::Controller undef - Mojolicious::Lite undef - Mojolicious::Plugin undef - Mojolicious::Plugin::Config undef - Mojolicious::Plugin::DefaultHelpers undef - Mojolicious::Plugin::EPLRenderer undef - Mojolicious::Plugin::EPRenderer undef - Mojolicious::Plugin::HeaderCondition undef - Mojolicious::Plugin::JSONConfig undef - Mojolicious::Plugin::Mount undef - Mojolicious::Plugin::NotYAMLConfig undef - Mojolicious::Plugin::TagHelpers undef - Mojolicious::Plugins undef - Mojolicious::Renderer undef - Mojolicious::Routes undef - Mojolicious::Routes::Match undef - Mojolicious::Routes::Pattern undef - Mojolicious::Routes::Route undef - Mojolicious::Sessions undef - Mojolicious::Static undef - Mojolicious::Types undef - Mojolicious::Validator undef - Mojolicious::Validator::Validation undef - Test::Mojo undef - ojo undef - requirements: - ExtUtils::MakeMaker 0 - IO::Socket::IP 0.37 - Sub::Util 1.41 - perl 5.016 - Moo-2.005005 - pathname: H/HA/HAARG/Moo-2.005005.tar.gz - provides: - Method::Generate::Accessor undef - Method::Generate::BuildAll undef - Method::Generate::Constructor undef - Method::Generate::DemolishAll undef - Moo 2.005005 - Moo::HandleMoose undef - Moo::HandleMoose::FakeConstructor undef - Moo::HandleMoose::FakeMetaClass undef - Moo::HandleMoose::_TypeMap undef - Moo::Object undef - Moo::Role 2.005005 - Moo::_Utils undef - Moo::sification undef - oo undef - requirements: - Carp 0 - Class::Method::Modifiers 1.10 - Exporter 0 - ExtUtils::MakeMaker 0 - Role::Tiny 2.002003 - Scalar::Util 1.00 - Sub::Defer 2.006006 - Sub::Quote 2.006006 - perl 5.006 - Role-Tiny-2.002004 - pathname: H/HA/HAARG/Role-Tiny-2.002004.tar.gz - provides: - Role::Tiny 2.002004 - Role::Tiny::With 2.002004 - requirements: - Exporter 5.57 - perl 5.006 - SQL-Abstract-2.000001 - pathname: M/MS/MSTROUT/SQL-Abstract-2.000001.tar.gz - provides: - Chunkstrumenter undef - DBIx::Class::SQLMaker::Role::SQLA2Passthrough undef - SQL::Abstract 2.000001 - SQL::Abstract::Formatter undef - SQL::Abstract::Parts undef - SQL::Abstract::Plugin::BangOverrides undef - SQL::Abstract::Plugin::ExtraClauses undef - SQL::Abstract::Reference undef - SQL::Abstract::Role::Plugin undef - SQL::Abstract::Test undef - SQL::Abstract::Tree undef - requirements: - Exporter 5.57 - ExtUtils::MakeMaker 0 - Hash::Merge 0.12 - List::Util 0 - MRO::Compat 0.12 - Moo 2.000001 - Scalar::Util 0 - Sub::Quote 2.000001 - Test::Builder::Module 0.84 - Test::Deep 0.101 - Text::Balanced 2.00 - perl 5.006 - SQL-Abstract-Pg-1.0 - pathname: S/SR/SRI/SQL-Abstract-Pg-1.0.tar.gz - provides: - SQL::Abstract::Pg 1.0 - requirements: - ExtUtils::MakeMaker 0 - SQL::Abstract 2.0 - perl 5.016 - Sub-Quote-2.006008 - pathname: H/HA/HAARG/Sub-Quote-2.006008.tar.gz - provides: - Sub::Defer 2.006008 - Sub::Quote 2.006008 - requirements: - ExtUtils::MakeMaker 0 - Scalar::Util 0 - perl 5.006 - Test-Deep-1.204 - pathname: R/RJ/RJBS/Test-Deep-1.204.tar.gz - provides: - Test::Deep 1.204 - Test::Deep::All 1.204 - Test::Deep::Any 1.204 - Test::Deep::Array 1.204 - Test::Deep::ArrayEach 1.204 - Test::Deep::ArrayElementsOnly 1.204 - Test::Deep::ArrayLength 1.204 - Test::Deep::ArrayLengthOnly 1.204 - Test::Deep::Blessed 1.204 - Test::Deep::Boolean 1.204 - Test::Deep::Cache 1.204 - Test::Deep::Cache::Simple 1.204 - Test::Deep::Class 1.204 - Test::Deep::Cmp 1.204 - Test::Deep::Code 1.204 - Test::Deep::Hash 1.204 - Test::Deep::HashEach 1.204 - Test::Deep::HashElements 1.204 - Test::Deep::HashKeys 1.204 - Test::Deep::HashKeysOnly 1.204 - Test::Deep::Ignore 1.204 - Test::Deep::Isa 1.204 - Test::Deep::ListMethods 1.204 - Test::Deep::MM 1.204 - Test::Deep::Methods 1.204 - Test::Deep::NoTest 1.204 - Test::Deep::None 1.204 - Test::Deep::Number 1.204 - Test::Deep::Obj 1.204 - Test::Deep::Ref 1.204 - Test::Deep::RefType 1.204 - Test::Deep::Regexp 1.204 - Test::Deep::RegexpMatches 1.204 - Test::Deep::RegexpOnly 1.204 - Test::Deep::RegexpRef 1.204 - Test::Deep::RegexpRefOnly 1.204 - Test::Deep::RegexpVersion 1.204 - Test::Deep::ScalarRef 1.204 - Test::Deep::ScalarRefOnly 1.204 - Test::Deep::Set 1.204 - Test::Deep::Shallow 1.204 - Test::Deep::Stack 1.204 - Test::Deep::String 1.204 - Test::Deep::SubHash 1.204 - Test::Deep::SubHashElements 1.204 - Test::Deep::SubHashKeys 1.204 - Test::Deep::SubHashKeysOnly 1.204 - Test::Deep::SuperHash 1.204 - Test::Deep::SuperHashElements 1.204 - Test::Deep::SuperHashKeys 1.204 - Test::Deep::SuperHashKeysOnly 1.204 - requirements: - ExtUtils::MakeMaker 6.78 - List::Util 1.09 - Scalar::Util 1.09 - Test::Builder 0 - Test::More 0.96 - perl 5.012 - common-sense-3.75 - pathname: M/ML/MLEHMANN/common-sense-3.75.tar.gz - provides: - common::sense 3.75 - requirements: - ExtUtils::MakeMaker 0 diff --git a/frameworks/Perl/mojolicious/mojolicious.dockerfile b/frameworks/Perl/mojolicious/mojolicious.dockerfile index 1fec0cc3952..9e80b10096d 100644 --- a/frameworks/Perl/mojolicious/mojolicious.dockerfile +++ b/frameworks/Perl/mojolicious/mojolicious.dockerfile @@ -1,8 +1,8 @@ -FROM perl:5.40 +FROM perl:5.42 WORKDIR /mojo -ADD ./cpanfile* ./ +COPY cpanfile* . ENV PERL_CARTON_PATH=/mojo/local ENV PERL5LIB=${PERL_CARTON_PATH}/lib/perl5 @@ -14,9 +14,8 @@ RUN carton install --cpanfile /mojo/cpanfile ENV LIBEV_FLAGS=7 -ADD ./app.pl ./ +COPY app.pl . EXPOSE 8080 CMD hypnotoad -f /mojo/app.pl - diff --git a/frameworks/Perl/plack/plack-async.dockerfile b/frameworks/Perl/plack/plack-async.dockerfile index 8ef1ac76b04..a8adc5274e3 100644 --- a/frameworks/Perl/plack/plack-async.dockerfile +++ b/frameworks/Perl/plack/plack-async.dockerfile @@ -1,4 +1,4 @@ -FROM perl:latest +FROM perl:5.42 RUN apt-get update -yqq && apt-get install -yqq nginx RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::MariaDB diff --git a/frameworks/Perl/plack/plack.dockerfile b/frameworks/Perl/plack/plack.dockerfile index a0391f2f4ca..25e4e41ebe2 100644 --- a/frameworks/Perl/plack/plack.dockerfile +++ b/frameworks/Perl/plack/plack.dockerfile @@ -1,4 +1,4 @@ -FROM perl:latest +FROM perl:5.42 RUN apt-get update -yqq && apt-get install -yqq nginx RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::MariaDB diff --git a/frameworks/Python/aiohttp/app/views.py b/frameworks/Python/aiohttp/app/views.py index 91366d66eb7..cd8fa78e2eb 100644 --- a/frameworks/Python/aiohttp/app/views.py +++ b/frameworks/Python/aiohttp/app/views.py @@ -21,8 +21,6 @@ def json_response(payload): content_type="application/json", ) -ADDITIONAL_FORTUNE_ORM = Fortune(id=0, message='Additional fortune added at request time.') -ADDITIONAL_FORTUNE_ROW = {'id': 0, 'message': 'Additional fortune added at request time.'} READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' READ_SELECT_ORM = select(World.randomnumber).where(World.id == bindparam("id")) READ_FORTUNES_ORM = select(Fortune.id, Fortune.message) @@ -112,7 +110,7 @@ async def fortunes(request): async with request.app['db_session']() as sess: ret = await sess.execute(READ_FORTUNES_ORM) fortunes = ret.all() - fortunes.append(ADDITIONAL_FORTUNE_ORM) + fortunes.append(Fortune(id=0, message='Additional fortune added at request time.')) fortunes.sort(key=sort_fortunes_orm) content = template.render(fortunes=fortunes) return Response(text=content, content_type='text/html') @@ -124,7 +122,7 @@ async def fortunes_raw(request): """ async with request.app['pg'].acquire() as conn: fortunes = await conn.fetch('SELECT * FROM Fortune') - fortunes.append(ADDITIONAL_FORTUNE_ROW) + fortunes.append({'id': 0, 'message': 'Additional fortune added at request time.'}) fortunes.sort(key=sort_fortunes_raw) content = template.render(fortunes=fortunes) return Response(text=content, content_type='text/html') diff --git a/frameworks/Python/aiohttp/requirements-cpython.txt b/frameworks/Python/aiohttp/requirements-cpython.txt index f49e01d17d2..993aca78ac8 100644 --- a/frameworks/Python/aiohttp/requirements-cpython.txt +++ b/frameworks/Python/aiohttp/requirements-cpython.txt @@ -2,5 +2,5 @@ asyncpg==0.30.0 gunicorn==23.0.0 -orjson==3.10.16 +orjson==3.11.6 uvloop==0.21.0 diff --git a/frameworks/Python/aiohttp/requirements.txt b/frameworks/Python/aiohttp/requirements.txt index c5c5d4e3eb2..a5db21887ff 100644 --- a/frameworks/Python/aiohttp/requirements.txt +++ b/frameworks/Python/aiohttp/requirements.txt @@ -1,3 +1,3 @@ -aiohttp==3.12.14 +aiohttp==3.13.3 jinja2==3.1.6 SQLAlchemy==2.0.40 diff --git a/frameworks/Python/aioworkers/pg.py b/frameworks/Python/aioworkers/pg.py index e2ec0cbea21..127edea4309 100644 --- a/frameworks/Python/aioworkers/pg.py +++ b/frameworks/Python/aioworkers/pg.py @@ -12,7 +12,6 @@ READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, "Additional fortune added at request time."] sort_fortunes_key = itemgetter(1) logger = logging.getLogger(__name__) @@ -73,7 +72,7 @@ async def fortunes(context, request): async with context.pg.pool.acquire() as connection: fortunes = await connection.fetch("SELECT * FROM Fortune") - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, "Additional fortune added at request time."]) fortunes.sort(key=sort_fortunes_key) content = context.templates.fortune.render(fortunes=fortunes) diff --git a/frameworks/Python/api_hour/README.md b/frameworks/Python/api_hour/README.md deleted file mode 100644 index 72f27c13f80..00000000000 --- a/frameworks/Python/api_hour/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# AsyncIO/aiohttp/API-Hour Benchmark Test - -This is the AsyncIO/aiohttp/API-Hour portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to AsyncIO/API-Hour. For further guidance, -review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). -Also note that there is additional information provided in -the [Python README](../). - -## Test Paths & Sources - -* [JSON Serialization](aiohttp.web/hello/endpoints/world.py): "/json" -* [Single Database Query](aiohttp.web/hello/services/world.py): "/db" -* [Multiple Database Queries](aiohttp.web/hello/services/world.py): "/queries?queries=#"* -* [Fortunes](aiohttp.web/hello/services/world.py): "/fortunes" -* [Database Updates](aiohttp.web/hello/services/world.py): "/updates?queries=#"* -* [Plaintext](aiohttp.web/hello/endpoints/world.py): "/plaintext" - -*Replace # with an actual number. - -## Get Help - -### Community - -* [API-Hour Google Group](https://groups.google.com/forum/#!forum/api-hour) - -### Resources - -* [API-Hour Source Code](https://github.com/Eyepea/API-Hour) diff --git a/frameworks/Python/api_hour/aiohttp.web/LICENSE b/frameworks/Python/api_hour/aiohttp.web/LICENSE deleted file mode 100644 index 41a9656a9c6..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright [2015] [Eyepea Dev Team] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/gunicorn_conf.py b/frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/gunicorn_conf.py deleted file mode 100644 index 64767c70cc8..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/gunicorn_conf.py +++ /dev/null @@ -1,15 +0,0 @@ -import multiprocessing -import os - -_is_travis = os.environ.get('TRAVIS') == 'true' - -workers = multiprocessing.cpu_count() -if _is_travis: - workers = 2 - -bind = ['0.0.0.0:8080'] -keepalive = 120 -errorlog = '-' -pidfile = '/tmp/api_hour.pid' -pythonpath = 'hello' -backlog = 10240000 diff --git a/frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/logging.ini b/frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/logging.ini deleted file mode 100644 index 581435cbd23..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/logging.ini +++ /dev/null @@ -1,71 +0,0 @@ -[formatters] -keys=detailed,simple - -[handlers] -keys=console,syslog,smtp - -[loggers] -keys=root,warnings,asyncio,gunicorn,aiohttp,api_hour,hello - -[formatter_simple] -format=%(name)s:%(levelname)s %(asctime)s %(module)s.py => %(message)s - -[formatter_detailed] -format=%(name)s:%(levelname)s %(asctime)s %(module)s.py:%(lineno)d => %(message)s - -[handler_console] -class=StreamHandler -args=(sys.stdout,) -formatter=detailed - -[handler_syslog] -class=handlers.SysLogHandler -args=('/dev/log', handlers.SysLogHandler.LOG_LOCAL6) -formatter=detailed - -[handler_smtp] -class=handlers.SMTPHandler -level=WARN -args=('127.0.0.1', 'gmludo@gmail.com', ['gmludo@gmail.com'], 'hello error on server: hello') -formatter=detailed - -[logger_root] -level=ERROR -handlers=console - -# You can add smtp in handlers list to receive e-mail alerts -[logger_warnings] -level=WARN -handlers=console -qualname=py.warnings -propagate=0 - -[logger_asyncio] -level=WARN -handlers=console -qualname=asyncio -propagate=0 - -[logger_gunicorn] -level=WARN -handlers=console -qualname=gunicorn -propagate=0 - -[logger_aiohttp] -level=WARN -handlers=console -qualname=aiohttp -propagate=0 - -[logger_api_hour] -level=WARN -handlers=console -qualname=api_hour -propagate=0 - -[logger_hello] -level=WARN -handlers=console -qualname=hello -propagate=0 diff --git a/frameworks/Python/api_hour/aiohttp.web/etc/hello/main/main.yaml b/frameworks/Python/api_hour/aiohttp.web/etc/hello/main/main.yaml deleted file mode 100644 index da8536c0c00..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/etc/hello/main/main.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -engines: - pg: - host: tfb-database - port: 5432 - dbname: hello_world - user: benchmarkdbuser - password: benchmarkdbpass - minsize: 22 - maxsize: 22 - mysql: - host: tfb-database - port: 3306 - db: hello_world - user: benchmarkdbuser - pwd: benchmarkdbpass - minsize: 22 - maxsize: 22 -#redis: -# host: tfb-database -# port: 6379 -# poolsize: 40 diff --git a/frameworks/Python/api_hour/aiohttp.web/etc/init.d/hello b/frameworks/Python/api_hour/aiohttp.web/etc/init.d/hello deleted file mode 100755 index 6b5eea7fcee..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/etc/init.d/hello +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -# -### BEGIN INIT INFO -# Provides: hello -# Required-Start: $local_fs $remote_fs $network $syslog -# Required-Stop: $local_fs $remote_fs $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Startup daemon script for hello -### END INIT INFO -# -# Author: Ludovic Gasc -set -e - -PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin -DAEMONNAME=hello -RUNDIR=/run/$DAEMONNAME -DAEMON=/opt/hello/${DAEMONNAME}_cli -PIDFILE=/run/lock/${DAEMONNAME}_0 -DAEMON_ARGS="" - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Create RUNDIR if it doesn't exist -[ -d "$RUNDIR" ] || mkdir -p "$RUNDIR" - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Load the VERBOSE setting and other rcS variables -[ -f /etc/default/rcS ] && . /etc/default/rcS - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. -. /lib/lsb/init-functions - -case "$1" in - start) - log_daemon_msg "Starting" "$DAEMONNAME" - if start-stop-daemon -b --start --pidfile $PIDFILE --startas $DAEMON -- $DAEMON_ARGS; - then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - stop) - log_daemon_msg "Stopping" "$DAEMONNAME" - if start-stop-daemon --stop --retry 5 --pidfile $PIDFILE; - then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - reload|force-reload) - log_daemon_msg "Reloading" "$DAEMONNAME" - if start-stop-daemon --stop --signal 1 --pidfile $PIDFILE --startas $DAEMON; - then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - restart) - $0 stop - $0 start - ;; - status) - status_of_proc -p $PIDFILE "$DAEMON" $DAEMONNAME && exit 0 || exit $? - ;; - *) - echo "Usage: $0 {start|stop|reload|force-reload|restart|status}" - exit 1 - ;; -esac - -exit 0 diff --git a/frameworks/Python/api_hour/aiohttp.web/etc/rsyslog.conf b/frameworks/Python/api_hour/aiohttp.web/etc/rsyslog.conf deleted file mode 100644 index 10798d600eb..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/etc/rsyslog.conf +++ /dev/null @@ -1,126 +0,0 @@ -# /etc/rsyslog.conf Configuration file for rsyslog. -# -# For more information see -# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html - - -################# -#### MODULES #### -################# - -$ModLoad imuxsock # provides support for local system logging -$ModLoad imklog # provides kernel logging support -#$ModLoad immark # provides --MARK-- message capability -$SystemLogRateLimitInterval 1 -$SystemLogRateLimitBurst 1000 - -# provides UDP syslog reception -#$ModLoad imudp -#$UDPServerRun 514 - -# provides TCP syslog reception -#$ModLoad imtcp -#$InputTCPServerRun 514 - - -########################### -#### GLOBAL DIRECTIVES #### -########################### - -# -# Use traditional timestamp format. -# To enable high precision timestamps, comment out the following line. -# -$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat - -# -# Set the default permissions for all log files. -# -$FileOwner root -$FileGroup adm -$FileCreateMode 0640 -$DirCreateMode 0755 -$Umask 0022 - -# -# Where to place spool and state files -# -$WorkDirectory /var/spool/rsyslog - -# -# Include all config files in /etc/rsyslog.d/ -# -$IncludeConfig /etc/rsyslog.d/*.conf - - -############### -#### RULES #### -############### - -# -# First some standard log files. Log by facility. -# -auth,authpriv.* /var/log/auth.log -*.*;auth,authpriv.none;\ - local6.none -/var/log/syslog -#cron.* /var/log/cron.log -daemon.* -/var/log/daemon.log -kern.* -/var/log/kern.log -lpr.* -/var/log/lpr.log -mail.* -/var/log/mail.log -user.* -/var/log/user.log - -local6.* /var/log/hello/hello.log - -# -# Logging for the mail system. Split it up so that -# it is easy to write scripts to parse these files. -# -mail.info -/var/log/mail.info -mail.warn -/var/log/mail.warn -mail.err /var/log/mail.err - -# -# Logging for INN news system. -# -news.crit /var/log/news/news.crit -news.err /var/log/news/news.err -news.notice -/var/log/news/news.notice - -# -# Some "catch-all" log files. -# -*.=debug;\ - auth,authpriv.none;\ - news.none;mail.none;local7.none -/var/log/debug -*.=info;*.=notice;*.=warn;\ - auth,authpriv.none;\ - cron,daemon.none;\ - mail,news.none;local7.none -/var/log/messages - -# -# Emergencies are sent to everybody logged in. -# -*.emerg :omusrmsg:* - -# -# I like to have messages displayed on the console, but only on a virtual -# console I usually leave idle. -# -#daemon,mail.*;\ -# news.=crit;news.=err;news.=notice;\ -# *.=debug;*.=info;\ -# *.=notice;*.=warn /dev/tty8 - -# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, -# you must invoke `xconsole' with the `-file' option: -# -# $ xconsole -file /dev/xconsole [...] -# -# NOTE: adjust the list below, or you'll go crazy if you have a reasonably -# busy site.. -# -daemon.*;mail.*;\ - news.err;\ - *.=debug;*.=info;\ - *.=notice;*.=warn |/dev/xconsole diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/__init__.py b/frameworks/Python/api_hour/aiohttp.web/hello/__init__.py deleted file mode 100644 index d42936daa86..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/__init__.py +++ /dev/null @@ -1,94 +0,0 @@ -import logging -import asyncio -import os - -import aiopg -import jinja2 -import psycopg2.extras -import aiohttp.web -import aiohttp_jinja2 -import aiomysql -import api_hour - -from . import endpoints - -LOG = logging.getLogger(__name__) - - -class Container(api_hour.Container): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Servers - self.servers['http'] = aiohttp.web.Application(loop=kwargs['loop']) - aiohttp_jinja2.setup(self.servers['http'], loader=jinja2.PackageLoader('hello')) - self.servers['http'].ah_container = self # keep a reference to Container - # routes - self.servers['http'].router.add_route('GET', '/json', endpoints.world.json) - self.servers['http'].router.add_route('GET', '/db', endpoints.world.db) - self.servers['http'].router.add_route('GET', '/db_mysql', endpoints.world.db_mysql) - self.servers['http'].router.add_route('GET', '/queries', endpoints.world.queries) - self.servers['http'].router.add_route('GET', '/queries_mysql', endpoints.world.queries_mysql) - self.servers['http'].router.add_route('GET', '/fortunes', endpoints.world.fortunes) - self.servers['http'].router.add_route('GET', '/fortunes_mysql', endpoints.world.fortunes_mysql) - self.servers['http'].router.add_route('GET', '/updates', endpoints.world.updates) - self.servers['http'].router.add_route('GET', '/updates_mysql', endpoints.world.updates_mysql) - self.servers['http'].router.add_route('GET', '/plaintext', endpoints.world.plaintext) - - def make_servers(self): - return [self.servers['http'].make_handler(logger=self.worker.log, - debug=False, - keep_alive=0, - access_log=None, - access_log_format=self.worker.cfg.access_log_format)] - - @asyncio.coroutine - def start(self): - yield from super().start() - LOG.info('Starting engines...') - print('Starting engines...') - self.engines['pg'] = self.loop.create_task(aiopg.create_pool(host='tfb-database', - port=int(self.config['engines']['pg']['port']), - sslmode='disable', - dbname=self.config['engines']['pg']['dbname'], - user=self.config['engines']['pg']['user'], - password=self.config['engines']['pg']['password'], - cursor_factory=psycopg2.extras.RealDictCursor, - minsize=int(self.config['engines']['pg']['minsize']), - maxsize=int(self.config['engines']['pg']['maxsize']), - loop=self.loop)) - self.engines['mysql'] = self.loop.create_task(aiomysql.create_pool( - host=self.config['engines']['mysql']['host'], - port=self.config['engines']['mysql']['port'], - user=self.config['engines']['mysql']['user'], - password=self.config['engines']['mysql']['pwd'], - db=self.config['engines']['mysql']['db'], - minsize=int(self.config['engines']['mysql']['minsize']), - maxsize=int(self.config['engines']['mysql']['maxsize']), - cursorclass=aiomysql.DictCursor, - charset='utf8', - use_unicode=True, - loop=self.loop)) - yield from asyncio.wait([self.engines['pg']], return_when=asyncio.ALL_COMPLETED) - - LOG.info('All engines ready !') - - @asyncio.coroutine - def stop(self): - LOG.info('Stopping engines...') - if 'pg' in self.engines: - if self.engines['pg'].done(): - self.engines['pg'].result().terminate() - yield from self.engines['pg'].result().wait_closed() - else: - yield from self.engines['pg'].cancel() - if 'mysql' in self.engines: - if self.engines['mysql'].done(): - self.engines['mysql'].result().close() - yield from self.engines['mysql'].result().wait_closed() - else: - yield from self.engines['mysql'].cancel() - if 'redis' in self.engines: - self.engines['redis'].close() - yield from asyncio.sleep(1) # wait redis close connection - LOG.info('All engines stopped !') - yield from super().stop() \ No newline at end of file diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/endpoints/__init__.py b/frameworks/Python/api_hour/aiohttp.web/hello/endpoints/__init__.py deleted file mode 100644 index 72e85908a10..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/endpoints/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import world \ No newline at end of file diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/endpoints/world.py b/frameworks/Python/api_hour/aiohttp.web/hello/endpoints/world.py deleted file mode 100644 index 331e741041e..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/endpoints/world.py +++ /dev/null @@ -1,86 +0,0 @@ -import logging -import asyncio - -from aiohttp.web import Response -from api_hour.plugins.aiohttp import JSON -import aiohttp_jinja2 - -from ..services import queries_number -from ..services.world import get_random_record, get_random_records, update_random_records, get_fortunes -from ..services import mysql - -LOG = logging.getLogger(__name__) - -@asyncio.coroutine -def json(request): - """Test type 1: JSON serialization""" - return JSON({'message': 'Hello, World!'}) - -@asyncio.coroutine -def db(request): - """Test type 2: Single database query""" - container = request.app.ah_container - - return JSON((yield from get_random_record(container))) - -@asyncio.coroutine -def db_mysql(request): - """Test type 2: Single database query""" - container = request.app.ah_container - - return JSON((yield from mysql.get_random_record(container))) - -@asyncio.coroutine -def queries(request): - """Test type 3: Multiple database queries""" - container = request.app.ah_container - limit = queries_number(request.GET.get('queries', 1)) - - return JSON((yield from get_random_records(container, limit))) - -@asyncio.coroutine -def queries_mysql(request): - """Test type 3: Multiple database queries""" - container = request.app.ah_container - limit = queries_number(request.GET.get('queries', 1)) - - return JSON((yield from mysql.get_random_records(container, limit))) - -@asyncio.coroutine -def fortunes(request): - """Test type 4: Fortunes""" - container = request.app.ah_container - - return aiohttp_jinja2.render_template('fortunes.html.j2', - request, - {'fortunes': (yield from get_fortunes(container))}) - -@asyncio.coroutine -def fortunes_mysql(request): - """Test type 4: Fortunes""" - container = request.app.ah_container - - return aiohttp_jinja2.render_template('fortunes.html.j2', - request, - {'fortunes': (yield from mysql.get_fortunes(container))}) - -@asyncio.coroutine -def updates(request): - """Test type 5: Database updates""" - container = request.app.ah_container - limit = queries_number(request.GET.get('queries', 1)) - - return JSON((yield from update_random_records(container, limit))) - -@asyncio.coroutine -def updates_mysql(request): - """Test type 5: Database updates""" - container = request.app.ah_container - limit = queries_number(request.GET.get('queries', 1)) - - return JSON((yield from mysql.update_random_records(container, limit))) - -@asyncio.coroutine -def plaintext(request): - """Test type 6: Plaintext""" - return Response(text='Hello, World!') \ No newline at end of file diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/services/__init__.py b/frameworks/Python/api_hour/aiohttp.web/hello/services/__init__.py deleted file mode 100644 index 9a1e89c1df7..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/services/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from . import world - -# get from Django hello application -def queries_number(number): - try: - queries = int(number) - except Exception: - queries = 1 - if queries < 1: - queries = 1 - if queries > 500: - queries = 500 - return queries - diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/services/mysql.py b/frameworks/Python/api_hour/aiohttp.web/hello/services/mysql.py deleted file mode 100644 index a681a73a49b..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/services/mysql.py +++ /dev/null @@ -1,58 +0,0 @@ -import asyncio -from random import randint -from operator import itemgetter - - -@asyncio.coroutine -def get_random_record(container): - with (yield from container.engines['mysql'].result()) as mysql_conn: - cur = yield from mysql_conn.cursor() - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - world = yield from cur.fetchone() - return world - - -@asyncio.coroutine -def get_random_records(container, limit): - results = [] - with (yield from container.engines['mysql'].result()) as mysql_conn: - cur = yield from mysql_conn.cursor() - for i in range(limit): - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - results.append((yield from cur.fetchone())) - - return results - - -@asyncio.coroutine -def update_random_records(container, limit): - results = [] - - with (yield from container.engines['mysql'].result()) as mysql_conn: - cur = yield from mysql_conn.cursor() - for i in range(limit): - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - world = yield from cur.fetchone() - world['RandomNumber'] = randint(1, 10000) - yield from cur.execute('UPDATE world SET randomnumber=%(random_number)s WHERE id=%(idx)s', - {'random_number': world['RandomNumber'], 'idx': world['Id']}) - yield from mysql_conn.commit() - results.append(world) - return results - - -@asyncio.coroutine -def get_fortunes(container): - with (yield from container.engines['mysql'].result()) as mysql_conn: - cur = yield from mysql_conn.cursor() - yield from cur.execute('SELECT * FROM fortune') - fortunes = yield from cur.fetchall() - - fortunes.append({'id': 0, 'message': 'Additional fortune added at request time.'}) - - fortunes.sort(key=itemgetter('message')) - - return fortunes diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/services/world.py b/frameworks/Python/api_hour/aiohttp.web/hello/services/world.py deleted file mode 100644 index bce4a5f5dc9..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/services/world.py +++ /dev/null @@ -1,55 +0,0 @@ -import asyncio -import sys -from random import randint -from operator import itemgetter - -@asyncio.coroutine -def get_random_record(container): - pg = yield from container.engines['pg'] - - with (yield from pg.cursor()) as cur: - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - world = yield from cur.fetchone() - return world - -@asyncio.coroutine -def get_random_records(container, limit): - pg = yield from container.engines['pg'] - results = [] - with (yield from pg.cursor()) as cur: - for i in range(limit): - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - results.append((yield from cur.fetchone())) - - return results - -@asyncio.coroutine -def update_random_records(container, limit): - results = [] - pg = yield from container.engines['pg'] - with (yield from pg.cursor()) as cur: - for i in range(limit): - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - world = yield from cur.fetchone() - world['RandomNumber'] = randint(1, 10000) - yield from cur.execute('UPDATE world SET randomnumber=%(random_number)s WHERE id=%(idx)s', - {'random_number': world['RandomNumber'], 'idx': world['Id']}) - results.append(world) - return results - -@asyncio.coroutine -def get_fortunes(container): - pg = yield from container.engines['pg'] - - with (yield from pg.cursor()) as cur: - yield from cur.execute('SELECT * FROM fortune') - fortunes = yield from cur.fetchall() - - fortunes.append({'id': 0, 'message': 'Additional fortune added at request time.'}) - - fortunes.sort(key=itemgetter('message')) - - return fortunes diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/templates/fortunes.html.j2 b/frameworks/Python/api_hour/aiohttp.web/hello/templates/fortunes.html.j2 deleted file mode 100644 index f402560b250..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/templates/fortunes.html.j2 +++ /dev/null @@ -1,20 +0,0 @@ - - - - Fortunes - - -
idmessage
'.$id.''.htmlspecialchars($fortune, ENT_QUOTES, 'utf-8').'
- - - - - {% for fortune in fortunes %} - - - - - {% endfor %} -
idmessage
{{ fortune['id']|e }}{{ fortune['message']|e }}
- - \ No newline at end of file diff --git a/frameworks/Python/api_hour/aiohttp.web/hello/utils/__init__.py b/frameworks/Python/api_hour/aiohttp.web/hello/utils/__init__.py deleted file mode 100644 index f686a6b20d7..00000000000 --- a/frameworks/Python/api_hour/aiohttp.web/hello/utils/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import logging - -LOG = logging.getLogger(__name__) \ No newline at end of file diff --git a/frameworks/Python/api_hour/api_hour-dbs.dockerfile b/frameworks/Python/api_hour/api_hour-dbs.dockerfile deleted file mode 100644 index 82b79cd47c9..00000000000 --- a/frameworks/Python/api_hour/api_hour-dbs.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./yocto_http /yocto_http -ADD ./requirements.txt /yocto_http - -WORKDIR /yocto_http - -RUN pip3 install -r /yocto_http/requirements.txt - -WORKDIR /yocto_http - -EXPOSE 8081 - -CMD api_hour -ac hello:Container diff --git a/frameworks/Python/api_hour/api_hour-json.dockerfile b/frameworks/Python/api_hour/api_hour-json.dockerfile deleted file mode 100644 index 94154c18e38..00000000000 --- a/frameworks/Python/api_hour/api_hour-json.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./yocto_http /yocto_http -ADD ./requirements.txt /yocto_http - -WORKDIR /yocto_http - -RUN pip3 install -r /yocto_http/requirements.txt - -WORKDIR /yocto_http - -EXPOSE 8080 - -CMD api_hour -ac hello:Container diff --git a/frameworks/Python/api_hour/api_hour-mysql.dockerfile b/frameworks/Python/api_hour/api_hour-mysql.dockerfile deleted file mode 100644 index 4fe26f2aaab..00000000000 --- a/frameworks/Python/api_hour/api_hour-mysql.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./aiohttp.web /aiohttp.web -ADD ./requirements.txt /aiohttp.web - -WORKDIR /aiohttp.web - -RUN pip3 install -r /aiohttp.web/requirements.txt - -WORKDIR /aiohttp.web - -EXPOSE 8080 - -CMD api_hour -ac hello:Container diff --git a/frameworks/Python/api_hour/api_hour-plaintext.dockerfile b/frameworks/Python/api_hour/api_hour-plaintext.dockerfile deleted file mode 100644 index c9515178939..00000000000 --- a/frameworks/Python/api_hour/api_hour-plaintext.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./yocto_http /yocto_http -ADD ./requirements.txt /yocto_http - -WORKDIR /yocto_http - -RUN pip3 install -r /yocto_http/requirements.txt - -WORKDIR /yocto_http - -EXPOSE 8082 - -CMD api_hour -ac hello:Container diff --git a/frameworks/Python/api_hour/api_hour.dockerfile b/frameworks/Python/api_hour/api_hour.dockerfile deleted file mode 100644 index 4fe26f2aaab..00000000000 --- a/frameworks/Python/api_hour/api_hour.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./aiohttp.web /aiohttp.web -ADD ./requirements.txt /aiohttp.web - -WORKDIR /aiohttp.web - -RUN pip3 install -r /aiohttp.web/requirements.txt - -WORKDIR /aiohttp.web - -EXPOSE 8080 - -CMD api_hour -ac hello:Container diff --git a/frameworks/Python/api_hour/benchmark_config.json b/frameworks/Python/api_hour/benchmark_config.json deleted file mode 100644 index eb5cb9970b4..00000000000 --- a/frameworks/Python/api_hour/benchmark_config.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "framework": "api_hour", - "tests": [{ - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "api_hour", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "API-Hour-PG", - "notes": "Python 3 + API-Hour + AsyncIO + aiohttp + PostgreSQL", - "tags": ["broken"] - }, - "mysql": { - "db_url": "/db_mysql", - "query_url": "/queries_mysql?queries=", - "fortune_url": "/fortunes_mysql", - "update_url": "/updates_mysql?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "api_hour", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "API-Hour-MySQL", - "notes": "Python 3 + API-Hour + AsyncIO + aiohttp + MySQL", - "tags": ["broken"] - }, - "json": { - "json_url": "/json", - "port": 8080, - "approach": "Stripped", - "classification": "Platform", - "database": "None", - "framework": "api_hour", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "API-Hour-yocto", - "notes": "Python 3 + API-Hour + AsyncIO", - "tags": ["broken"] - }, - "dbs": { - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8081, - "approach": "Stripped", - "classification": "Platform", - "database": "Postgres", - "framework": "api_hour", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "API-Hour-yocto", - "notes": "Python 3 + API-Hour + AsyncIO", - "tags": ["broken"] - }, - "plaintext": { - "plaintext_url": "/plaintext", - "port": 8082, - "approach": "Stripped", - "classification": "Platform", - "database": "None", - "framework": "api_hour", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "API-Hour-yocto", - "notes": "Python 3 + API-Hour + AsyncIO", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Python/api_hour/config.toml b/frameworks/Python/api_hour/config.toml deleted file mode 100644 index aaff808cd3c..00000000000 --- a/frameworks/Python/api_hour/config.toml +++ /dev/null @@ -1,72 +0,0 @@ -[framework] -name = "api_hour" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "asyncio" -webserver = "Gunicorn" -versus = "None" - -[plaintext] -urls.plaintext = "/plaintext" -approach = "Stripped" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "asyncio" -webserver = "Gunicorn" -versus = "None" - -[json] -urls.json = "/json" -approach = "Stripped" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "asyncio" -webserver = "Gunicorn" -versus = "None" - -[dbs] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Stripped" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "asyncio" -webserver = "Gunicorn" -versus = "None" - -[mysql] -urls.db = "/db_mysql" -urls.query = "/queries_mysql?queries=" -urls.update = "/updates_mysql?queries=" -urls.fortune = "/fortunes_mysql" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "asyncio" -webserver = "Gunicorn" -versus = "None" diff --git a/frameworks/Python/api_hour/requirements.txt b/frameworks/Python/api_hour/requirements.txt deleted file mode 100644 index c39d8dc9404..00000000000 --- a/frameworks/Python/api_hour/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -aiohttp==3.12.14 --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 -asyncio-redis==0.13.4 -chardet==2.3.0 -gunicorn==23.0.0 -hiredis==0.2.0 -Jinja2==3.1.6 -MarkupSafe==0.23 -piprot==0.9.1 -psycopg2==2.7.5 -PyYAML==5.4 -requests==2.32.4 -requests-futures==0.9.5 -setproctitle==1.1.8 -ujson==1.33 -aiomysql==0.3.0 -PyMySQL==1.1.1 diff --git a/frameworks/Python/api_hour/yocto_http/LICENSE b/frameworks/Python/api_hour/yocto_http/LICENSE deleted file mode 100644 index 41a9656a9c6..00000000000 --- a/frameworks/Python/api_hour/yocto_http/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright [2015] [Eyepea Dev Team] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/etc/default/hello b/frameworks/Python/api_hour/yocto_http/etc/default/hello deleted file mode 100644 index cc1ca1925fb..00000000000 --- a/frameworks/Python/api_hour/yocto_http/etc/default/hello +++ /dev/null @@ -1,3 +0,0 @@ -# Start the daemon by default, let the user disable it. -START_DAEMON=yes -DAEMON_ARGS="--config_dir=/etc/hello" \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/gunicorn_conf.py b/frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/gunicorn_conf.py deleted file mode 100644 index 029e2fcd673..00000000000 --- a/frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/gunicorn_conf.py +++ /dev/null @@ -1,15 +0,0 @@ -import multiprocessing -import os - -_is_travis = os.environ.get('TRAVIS') == 'true' - -workers = multiprocessing.cpu_count() -if _is_travis: - workers = 2 - -bind = ['0.0.0.0:8080', '0.0.0.0:8081', '0.0.0.0:8082'] -keepalive = 120 -errorlog = '-' -pidfile = '/tmp/api_hour.pid' -pythonpath = 'hello' -backlog = 10240000 \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/logging.ini b/frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/logging.ini deleted file mode 100644 index 581435cbd23..00000000000 --- a/frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/logging.ini +++ /dev/null @@ -1,71 +0,0 @@ -[formatters] -keys=detailed,simple - -[handlers] -keys=console,syslog,smtp - -[loggers] -keys=root,warnings,asyncio,gunicorn,aiohttp,api_hour,hello - -[formatter_simple] -format=%(name)s:%(levelname)s %(asctime)s %(module)s.py => %(message)s - -[formatter_detailed] -format=%(name)s:%(levelname)s %(asctime)s %(module)s.py:%(lineno)d => %(message)s - -[handler_console] -class=StreamHandler -args=(sys.stdout,) -formatter=detailed - -[handler_syslog] -class=handlers.SysLogHandler -args=('/dev/log', handlers.SysLogHandler.LOG_LOCAL6) -formatter=detailed - -[handler_smtp] -class=handlers.SMTPHandler -level=WARN -args=('127.0.0.1', 'gmludo@gmail.com', ['gmludo@gmail.com'], 'hello error on server: hello') -formatter=detailed - -[logger_root] -level=ERROR -handlers=console - -# You can add smtp in handlers list to receive e-mail alerts -[logger_warnings] -level=WARN -handlers=console -qualname=py.warnings -propagate=0 - -[logger_asyncio] -level=WARN -handlers=console -qualname=asyncio -propagate=0 - -[logger_gunicorn] -level=WARN -handlers=console -qualname=gunicorn -propagate=0 - -[logger_aiohttp] -level=WARN -handlers=console -qualname=aiohttp -propagate=0 - -[logger_api_hour] -level=WARN -handlers=console -qualname=api_hour -propagate=0 - -[logger_hello] -level=WARN -handlers=console -qualname=hello -propagate=0 diff --git a/frameworks/Python/api_hour/yocto_http/etc/hello/main/main.yaml b/frameworks/Python/api_hour/yocto_http/etc/hello/main/main.yaml deleted file mode 100644 index 480b7d8ac3f..00000000000 --- a/frameworks/Python/api_hour/yocto_http/etc/hello/main/main.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -engines: - pg: - host: tfb-database - port: 5432 - dbname: hello_world - user: benchmarkdbuser - password: benchmarkdbpass - minsize: 22 - maxsize: 22 diff --git a/frameworks/Python/api_hour/yocto_http/etc/init.d/hello b/frameworks/Python/api_hour/yocto_http/etc/init.d/hello deleted file mode 100755 index 6b5eea7fcee..00000000000 --- a/frameworks/Python/api_hour/yocto_http/etc/init.d/hello +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -# -### BEGIN INIT INFO -# Provides: hello -# Required-Start: $local_fs $remote_fs $network $syslog -# Required-Stop: $local_fs $remote_fs $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Startup daemon script for hello -### END INIT INFO -# -# Author: Ludovic Gasc -set -e - -PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin -DAEMONNAME=hello -RUNDIR=/run/$DAEMONNAME -DAEMON=/opt/hello/${DAEMONNAME}_cli -PIDFILE=/run/lock/${DAEMONNAME}_0 -DAEMON_ARGS="" - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Create RUNDIR if it doesn't exist -[ -d "$RUNDIR" ] || mkdir -p "$RUNDIR" - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Load the VERBOSE setting and other rcS variables -[ -f /etc/default/rcS ] && . /etc/default/rcS - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. -. /lib/lsb/init-functions - -case "$1" in - start) - log_daemon_msg "Starting" "$DAEMONNAME" - if start-stop-daemon -b --start --pidfile $PIDFILE --startas $DAEMON -- $DAEMON_ARGS; - then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - stop) - log_daemon_msg "Stopping" "$DAEMONNAME" - if start-stop-daemon --stop --retry 5 --pidfile $PIDFILE; - then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - reload|force-reload) - log_daemon_msg "Reloading" "$DAEMONNAME" - if start-stop-daemon --stop --signal 1 --pidfile $PIDFILE --startas $DAEMON; - then - log_end_msg 0 - else - log_end_msg 1 - fi - ;; - restart) - $0 stop - $0 start - ;; - status) - status_of_proc -p $PIDFILE "$DAEMON" $DAEMONNAME && exit 0 || exit $? - ;; - *) - echo "Usage: $0 {start|stop|reload|force-reload|restart|status}" - exit 1 - ;; -esac - -exit 0 diff --git a/frameworks/Python/api_hour/yocto_http/etc/rsyslog.conf b/frameworks/Python/api_hour/yocto_http/etc/rsyslog.conf deleted file mode 100644 index 10798d600eb..00000000000 --- a/frameworks/Python/api_hour/yocto_http/etc/rsyslog.conf +++ /dev/null @@ -1,126 +0,0 @@ -# /etc/rsyslog.conf Configuration file for rsyslog. -# -# For more information see -# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html - - -################# -#### MODULES #### -################# - -$ModLoad imuxsock # provides support for local system logging -$ModLoad imklog # provides kernel logging support -#$ModLoad immark # provides --MARK-- message capability -$SystemLogRateLimitInterval 1 -$SystemLogRateLimitBurst 1000 - -# provides UDP syslog reception -#$ModLoad imudp -#$UDPServerRun 514 - -# provides TCP syslog reception -#$ModLoad imtcp -#$InputTCPServerRun 514 - - -########################### -#### GLOBAL DIRECTIVES #### -########################### - -# -# Use traditional timestamp format. -# To enable high precision timestamps, comment out the following line. -# -$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat - -# -# Set the default permissions for all log files. -# -$FileOwner root -$FileGroup adm -$FileCreateMode 0640 -$DirCreateMode 0755 -$Umask 0022 - -# -# Where to place spool and state files -# -$WorkDirectory /var/spool/rsyslog - -# -# Include all config files in /etc/rsyslog.d/ -# -$IncludeConfig /etc/rsyslog.d/*.conf - - -############### -#### RULES #### -############### - -# -# First some standard log files. Log by facility. -# -auth,authpriv.* /var/log/auth.log -*.*;auth,authpriv.none;\ - local6.none -/var/log/syslog -#cron.* /var/log/cron.log -daemon.* -/var/log/daemon.log -kern.* -/var/log/kern.log -lpr.* -/var/log/lpr.log -mail.* -/var/log/mail.log -user.* -/var/log/user.log - -local6.* /var/log/hello/hello.log - -# -# Logging for the mail system. Split it up so that -# it is easy to write scripts to parse these files. -# -mail.info -/var/log/mail.info -mail.warn -/var/log/mail.warn -mail.err /var/log/mail.err - -# -# Logging for INN news system. -# -news.crit /var/log/news/news.crit -news.err /var/log/news/news.err -news.notice -/var/log/news/news.notice - -# -# Some "catch-all" log files. -# -*.=debug;\ - auth,authpriv.none;\ - news.none;mail.none;local7.none -/var/log/debug -*.=info;*.=notice;*.=warn;\ - auth,authpriv.none;\ - cron,daemon.none;\ - mail,news.none;local7.none -/var/log/messages - -# -# Emergencies are sent to everybody logged in. -# -*.emerg :omusrmsg:* - -# -# I like to have messages displayed on the console, but only on a virtual -# console I usually leave idle. -# -#daemon,mail.*;\ -# news.=crit;news.=err;news.=notice;\ -# *.=debug;*.=info;\ -# *.=notice;*.=warn /dev/tty8 - -# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, -# you must invoke `xconsole' with the `-file' option: -# -# $ xconsole -file /dev/xconsole [...] -# -# NOTE: adjust the list below, or you'll go crazy if you have a reasonably -# busy site.. -# -daemon.*;mail.*;\ - news.err;\ - *.=debug;*.=info;\ - *.=notice;*.=warn |/dev/xconsole diff --git a/frameworks/Python/api_hour/yocto_http/hello/__init__.py b/frameworks/Python/api_hour/yocto_http/hello/__init__.py deleted file mode 100644 index 51c26b70cce..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/__init__.py +++ /dev/null @@ -1,63 +0,0 @@ -import logging -import asyncio -import os - -import aiopg -import jinja2 -import psycopg2.extras -import api_hour - -from . import endpoints -from . import servers -from .utils import yocto_http - -LOG = logging.getLogger(__name__) - - -class Container(api_hour.Container): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.servers['http'] = yocto_http.Application(loop=kwargs['loop']) - self.servers['http'].ah_container = self # keep a reference to Container - # routes - self.servers['http'].add_route('/db', endpoints.world.db) - self.servers['http'].add_route('/queries', endpoints.world.queries) - self.servers['http'].add_route('/fortunes', endpoints.world.fortunes, content_type='text/html; charset=UTF-8') - self.servers['http'].add_route('/updates', endpoints.world.updates) - self.servers['http']['j2_env'] = jinja2.Environment(loader=jinja2.PackageLoader('hello')) - - def make_servers(self): - return [servers.yocto_http.YoctoHttpJson, - self.servers['http'].handler, - servers.yocto_http.YoctoHttpText] - - @asyncio.coroutine - def start(self): - yield from super().start() - LOG.info('Starting engines...') - self.engines['pg'] = self.loop.create_task(aiopg.create_pool(host='tfb-database', - port=int(self.config['engines']['pg']['port']), - sslmode='disable', - dbname=self.config['engines']['pg']['dbname'], - user=self.config['engines']['pg']['user'], - password=self.config['engines']['pg']['password'], - cursor_factory=psycopg2.extras.RealDictCursor, - minsize=int(self.config['engines']['pg']['minsize']), - maxsize=int(self.config['engines']['pg']['maxsize']), - loop=self.loop)) - yield from asyncio.wait([self.engines['pg']], return_when=asyncio.ALL_COMPLETED) - - LOG.info('All engines ready !') - - @asyncio.coroutine - def stop(self): - LOG.info('Stopping engines...') - if 'pg' in self.engines: - if self.engines['pg'].done(): - self.engines['pg'].result().terminate() - yield from self.engines['pg'].result().wait_closed() - else: - yield from self.engines['pg'].cancel() - - LOG.info('All engines stopped !') - yield from super().stop() \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/endpoints/__init__.py b/frameworks/Python/api_hour/yocto_http/hello/endpoints/__init__.py deleted file mode 100644 index 72e85908a10..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/endpoints/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import world \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/endpoints/world.py b/frameworks/Python/api_hour/yocto_http/hello/endpoints/world.py deleted file mode 100644 index cc4f7655542..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/endpoints/world.py +++ /dev/null @@ -1,38 +0,0 @@ -import logging -import asyncio -import ujson - -from ..services import queries_number -from ..services.world import get_random_record, get_random_records, update_random_records, get_fortunes - -LOG = logging.getLogger(__name__) - -@asyncio.coroutine -def db(request): - """Test type 2: Single database query""" - container = request.app.ah_container - - return ujson.dumps((yield from get_random_record(container))) - -@asyncio.coroutine -def queries(request): - """Test type 3: Multiple database queries""" - container = request.app.ah_container - limit = queries_number(request.params.get('queries', 1)) - - return ujson.dumps((yield from get_random_records(container, limit))) - -@asyncio.coroutine -def fortunes(request): - """Test type 4: Fortunes""" - container = request.app.ah_container - template = request.app['j2_env'].get_template('fortunes.html.j2') - return template.render({'fortunes': (yield from get_fortunes(container))}) - -@asyncio.coroutine -def updates(request): - """Test type 5: Database updates""" - container = request.app.ah_container - limit = queries_number(request.params.get('queries', 1)) - - return ujson.dumps((yield from update_random_records(container, limit))) \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/servers/__init__.py b/frameworks/Python/api_hour/yocto_http/hello/servers/__init__.py deleted file mode 100644 index 136bc95b3bb..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/servers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import yocto_http \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/servers/yocto_http.py b/frameworks/Python/api_hour/yocto_http/hello/servers/yocto_http.py deleted file mode 100644 index ae1a6a35679..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/servers/yocto_http.py +++ /dev/null @@ -1,23 +0,0 @@ -import asyncio - -import ujson - -from ..utils.yocto_http.utils import generate_http_response - -class YoctoHttpJson(asyncio.Protocol): - def connection_made(self, transport): - self.transport = transport - - def data_received(self, data): - # self.transport.write(data) - payload = ujson.dumps({'message': 'Hello, World!'}) - self.transport.write(generate_http_response(payload)) - -class YoctoHttpText(asyncio.Protocol): - def connection_made(self, transport): - self.transport = transport - - def data_received(self, data): - # self.transport.write(data) - payload = 'Hello, World!' - self.transport.write(generate_http_response(payload, 'text/plain; charset=UTF-8')) \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/services/__init__.py b/frameworks/Python/api_hour/yocto_http/hello/services/__init__.py deleted file mode 100644 index 9a1e89c1df7..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/services/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from . import world - -# get from Django hello application -def queries_number(number): - try: - queries = int(number) - except Exception: - queries = 1 - if queries < 1: - queries = 1 - if queries > 500: - queries = 500 - return queries - diff --git a/frameworks/Python/api_hour/yocto_http/hello/services/world.py b/frameworks/Python/api_hour/yocto_http/hello/services/world.py deleted file mode 100644 index ed635a99837..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/services/world.py +++ /dev/null @@ -1,55 +0,0 @@ -import asyncio -from random import randint -from operator import itemgetter - -@asyncio.coroutine -def get_random_record(container): - pg = yield from container.engines['pg'] - - with (yield from pg.cursor()) as cur: - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - world = yield from cur.fetchone() - return world - -@asyncio.coroutine -def get_random_records(container, limit): - pg = yield from container.engines['pg'] - results = [] - with (yield from pg.cursor()) as cur: - for i in range(limit): - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - results.append((yield from cur.fetchone())) - - return results - -@asyncio.coroutine -def update_random_records(container, limit): - results = [] - pg = yield from container.engines['pg'] - - with (yield from pg.cursor()) as cur: - for i in range(limit): - yield from cur.execute('SELECT id AS "Id", randomnumber AS "RandomNumber" FROM world WHERE id=%(idx)s LIMIT 1', - {'idx': randint(1, 10000)}) - world = yield from cur.fetchone() - world['RandomNumber'] = randint(1, 10000) - yield from cur.execute('UPDATE world SET randomnumber=%(random_number)s WHERE id=%(idx)s', - {'random_number': world['RandomNumber'], 'idx': world['Id']}) - results.append(world) - return results - -@asyncio.coroutine -def get_fortunes(container): - pg = yield from container.engines['pg'] - - with (yield from pg.cursor()) as cur: - yield from cur.execute('SELECT * FROM fortune') - fortunes = yield from cur.fetchall() - - fortunes.append({'id': 0, 'message': 'Additional fortune added at request time.'}) - - fortunes.sort(key=itemgetter('message')) - - return fortunes \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/templates/fortunes.html.j2 b/frameworks/Python/api_hour/yocto_http/hello/templates/fortunes.html.j2 deleted file mode 100644 index f402560b250..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/templates/fortunes.html.j2 +++ /dev/null @@ -1,20 +0,0 @@ - - - - Fortunes - - - - - - - - {% for fortune in fortunes %} - - - - - {% endfor %} -
idmessage
{{ fortune['id']|e }}{{ fortune['message']|e }}
- - \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/utils/__init__.py b/frameworks/Python/api_hour/yocto_http/hello/utils/__init__.py deleted file mode 100644 index 905569002c6..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/utils/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import logging - -LOG = logging.getLogger(__name__) diff --git a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/__init__.py b/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/__init__.py deleted file mode 100644 index 57ad26ef886..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .application import Application \ No newline at end of file diff --git a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/application.py b/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/application.py deleted file mode 100644 index c8eb6f05f1c..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/application.py +++ /dev/null @@ -1,78 +0,0 @@ -import asyncio -import logging -from collections import OrderedDict - -from .request import Request -from .utils import generate_http_response - -log = logging.getLogger(__name__) - -class Application(dict): - - def __init__(self, default_encoding='utf-8', decode_headers=False, loop=None): - super(Application, self).__init__() - self.default_encoding = default_encoding - if loop is None: - loop = asyncio.get_event_loop() - self.decode_headers = decode_headers - self.loop = loop - self._route = OrderedDict() - - def add_route(self, path, endpoint, content_type='application/json'): - assert callable(endpoint), endpoint - if not asyncio.iscoroutinefunction(endpoint): - endpoint = asyncio.coroutine(endpoint) - endpoint.content_type = content_type - self._route[path] = endpoint - - @asyncio.coroutine - def handler(self, reader, writer): - # while True: - buffer = b'' - while b'\r\n\r\n' not in buffer: - buffer += yield from reader.read(100) - lines = buffer[:-2].decode(self.default_encoding).split('\r\n') - - url = lines[0].split(' ')[1].split('?') - path = url[0] - params = OrderedDict() - if len(url) == 2: - k, v = url[1].split('=', 1) # @TODO: support several parameters - params[k] = v - - # log.info('Received HTTP request from %r for "%s" route', - # writer.get_extra_info('peername'), - # uri) - - headers = {} - if self.decode_headers: - for line in lines: - k, v = line.split(': ', 1) - headers[k] = v - log.debug("HTTP Headers: %r", - headers) - - if path in self._route: - request = Request(app=self, - path=path, - params=params, - headers=headers, - reader=reader, writer=writer, - encoding=self.default_encoding) - try: - response = yield from self._route[path](request) - writer.write(generate_http_response(response, content_type=self._route[path].content_type)) - try: - yield from writer.drain() - except ConnectionError: - pass - except Exception as e: - log.exception(e) - else: - log.error('No route for the request "%s"', path) - writer.write(generate_http_response('')) - try: - yield from writer.drain() - except ConnectionError: - pass - writer.close() diff --git a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/request.py b/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/request.py deleted file mode 100644 index 753336e145f..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/request.py +++ /dev/null @@ -1,9 +0,0 @@ -class Request: - def __init__(self, app, path, params, headers, reader, writer, encoding='utf-8'): - self.app = app - self.path = path - self.params = params - self.headers = headers - self.reader = reader - self.writer = writer - self.encoding = encoding diff --git a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/utils.py b/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/utils.py deleted file mode 100644 index 27dea7d3603..00000000000 --- a/frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/utils.py +++ /dev/null @@ -1,11 +0,0 @@ -from wsgiref.handlers import format_date_time - -def generate_http_response(payload, content_type='application/json'): - return ("""HTTP/1.1 200 OK -CONTENT-TYPE: %s -CONTENT-LENGTH: %s -CONNECTION: keep-alive -DATE: %s -SERVER: yocto_http/0.0.2 - -%s""" % (content_type, len(payload), format_date_time(None), payload)).encode('utf-8') diff --git a/frameworks/Python/blacksheep/app-socketify.py b/frameworks/Python/blacksheep/app-socketify.py index d75fe084db3..27e3493fc56 100644 --- a/frameworks/Python/blacksheep/app-socketify.py +++ b/frameworks/Python/blacksheep/app-socketify.py @@ -12,7 +12,6 @@ from psqlpy import ConnectionPoolBuilder READ_ROW_SQL = 'SELECT "randomnumber" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, "Additional fortune added at request time."] CORE_COUNT = multiprocessing.cpu_count() MAX_DB_CONNECTIONS = 2000 @@ -97,7 +96,7 @@ async def fortunes_test(request): fortunes_fetch = await connection.fetch("SELECT * FROM Fortune") # fortunes = fortunes_fetch.result() fortunes = [list(item.values()) for item in fortunes_fetch.result()] - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, "Additional fortune added at request time."]) fortunes.sort(key=lambda row: row[1]) data = fortune_template.render(fortunes=fortunes) return bs.html(data) @@ -138,4 +137,4 @@ def create_fork(): for i in range(1, workers): create_fork() - run_app() \ No newline at end of file + run_app() diff --git a/frameworks/Python/blacksheep/app.py b/frameworks/Python/blacksheep/app.py index 80dd48919e9..7c00c1e648e 100644 --- a/frameworks/Python/blacksheep/app.py +++ b/frameworks/Python/blacksheep/app.py @@ -16,7 +16,6 @@ READ_ROW_SQL = 'SELECT "id", "randomnumber" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, "Additional fortune added at request time."] MAX_CONNECTIONS = 1900 CORE_COUNT = multiprocessing.cpu_count() MAX_POOL_SIZE = max(1,int(os.getenv('MAX_POOL_SIZE', MAX_CONNECTIONS // CORE_COUNT))) @@ -123,7 +122,7 @@ async def fortunes_test(request): async with db_pool.acquire() as db_conn: fortunes = await db_conn.fetch("SELECT * FROM Fortune") - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, "Additional fortune added at request time."]) fortunes.sort(key=lambda row: row[1]) data = fortune_template.render(fortunes=fortunes) return bs.html(data) @@ -173,4 +172,4 @@ def create_fork(): for i in range(1, workers): create_fork() - run_app() \ No newline at end of file + run_app() diff --git a/frameworks/Python/bottle/requirements-pypy.txt b/frameworks/Python/bottle/requirements-pypy.txt index 0e66864a04e..e5d7ac54ff2 100644 --- a/frameworks/Python/bottle/requirements-pypy.txt +++ b/frameworks/Python/bottle/requirements-pypy.txt @@ -3,4 +3,4 @@ bottle-sqlalchemy==0.4.3 gunicorn==23.0.0 PyMySQL==0.8.0 SQLAlchemy==1.3.0 -tornado==6.5 +tornado==6.5.5 diff --git a/frameworks/Python/django/benchmark_config.json b/frameworks/Python/django/benchmark_config.json index c4e3d51a143..1274ff8fcd0 100644 --- a/frameworks/Python/django/benchmark_config.json +++ b/frameworks/Python/django/benchmark_config.json @@ -1,89 +1,96 @@ { "framework": "django", - "tests": [{ - "default": { - "plaintext_url" : "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/dbs?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "django", - "language": "Python", - "flavor": "Python3", - "orm": "Full", - "platform": "WSGI", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "Django", - "notes": "", - "versus": "wsgi", - "tags": [ ] - }, - "socketify-wsgi": { - "plaintext_url" : "/plaintext", - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "None", - "framework": "django", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "WSGI", - "webserver": "Socketify.py", - "os": "Linux", - "database_os": "Linux", - "display_name": "Django [Socketify.py WSGI]", - "notes": "", - "versus": "wsgi" - }, - "socketify-wsgi-pypy": { - "plaintext_url" : "/plaintext", - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "None", - "framework": "django", - "language": "Python", - "flavor": "PyPy3", - "orm": "Raw", - "platform": "WSGI", - "webserver": "Socketify.py", - "os": "Linux", - "database_os": "Linux", - "display_name": "Django [Socketify.py WSGI PyPy3]", - "notes": "", - "versus": "wsgi" - }, - "postgresql": { - "db_url": "/db", - "query_url": "/dbs?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "django", - "language": "Python", - "flavor": "Python3", - "orm": "Full", - "platform": "WSGI", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "Django [Postgres]", - "notes": "", - "versus": "wsgi", - "tags": [ ] + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/dbs?queries=", + "fortune_url": "/fortunes", + "update_url": "/update?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "django", + "language": "Python", + "flavor": "Python3", + "orm": "Full", + "platform": "WSGI", + "webserver": "Gunicorn", + "os": "Linux", + "database_os": "Linux", + "display_name": "Django", + "notes": "", + "versus": "wsgi", + "tags": [] + }, + "socketify-wsgi": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "django", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "WSGI", + "webserver": "Socketify.py", + "os": "Linux", + "database_os": "Linux", + "display_name": "Django [Socketify.py WSGI]", + "notes": "", + "versus": "wsgi" + }, + "postgresql": { + "db_url": "/db", + "query_url": "/dbs?queries=", + "fortune_url": "/fortunes", + "update_url": "/update?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "django", + "language": "Python", + "flavor": "Python3", + "orm": "Full", + "platform": "WSGI", + "webserver": "Gunicorn", + "os": "Linux", + "database_os": "Linux", + "display_name": "Django [Postgres]", + "notes": "", + "versus": "wsgi", + "tags": [] + }, + "granian": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/dbs?queries=", + "fortune_url": "/fortunes", + "update_url": "/update?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "django", + "language": "Python", + "flavor": "Python3", + "orm": "Full", + "platform": "WSGI", + "webserver": "Granian", + "os": "Linux", + "database_os": "Linux", + "display_name": "Django [Granian]", + "notes": "", + "versus": "wsgi", + "tags": [] + } } - }] -} + ] +} \ No newline at end of file diff --git a/frameworks/Python/django/config.toml b/frameworks/Python/django/config.toml index 592e487389c..85ecc8f9e04 100644 --- a/frameworks/Python/django/config.toml +++ b/frameworks/Python/django/config.toml @@ -15,7 +15,7 @@ database_os = "Linux" os = "Linux" orm = "Full" platform = "WSGI" -webserver = "Meinheld" +webserver = "Gunicorn" versus = "wsgi" [socketify-wsgi] @@ -31,19 +31,6 @@ platform = "WSGI" webserver = "Socketify.py" versus = "wsgi" -[socketify-wsgi-pypy] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "WSGI" -webserver = "Socketify.py" -versus = "wsgi" - [postgresql] urls.db = "/db" urls.query = "/dbs?queries=" @@ -56,5 +43,5 @@ database_os = "Linux" os = "Linux" orm = "Full" platform = "WSGI" -webserver = "Meinheld" +webserver = "Gunicorn" versus = "wsgi" diff --git a/frameworks/Python/django/django-granian.dockerfile b/frameworks/Python/django/django-granian.dockerfile new file mode 100644 index 00000000000..e4a8c234f80 --- /dev/null +++ b/frameworks/Python/django/django-granian.dockerfile @@ -0,0 +1,14 @@ +FROM python:3.14 + +ADD ./ /django +WORKDIR /django +RUN pip install -r /django/requirements-granian.txt + +ENV PYTHONPATH=/django/hello +ENV DJANGO_DB=postgresql + +EXPOSE 8080 + +# Use WSGI mode - Django's sync ORM crashes workers in ASGI mode under load +# runtime-mode=mt for multi-threaded (same as TechEmpower) +CMD granian --interface wsgi hello.wsgi:application --host 0.0.0.0 --port 8080 --workers $(nproc) --backlog 16384 --blocking-threads 1 --runtime-mode mt diff --git a/frameworks/Python/django/django-postgresql.dockerfile b/frameworks/Python/django/django-postgresql.dockerfile index ff554710097..b6b6d7b5daf 100644 --- a/frameworks/Python/django/django-postgresql.dockerfile +++ b/frameworks/Python/django/django-postgresql.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12-bullseye +FROM python:3.14 ADD ./ /django diff --git a/frameworks/Python/django/django-socketify-wsgi-pypy.dockerfile b/frameworks/Python/django/django-socketify-wsgi-pypy.dockerfile deleted file mode 100644 index 54a2429a10c..00000000000 --- a/frameworks/Python/django/django-socketify-wsgi-pypy.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM pypy:3.9-bullseye - -ADD ./ /django - -WORKDIR /django -RUN apt-get update; apt-get install libuv1 -y -RUN pip install -r /django/requirements-socketify.txt - -EXPOSE 8080 - -CMD python ./django-socketify-wsgi.py diff --git a/frameworks/Python/django/django-socketify-wsgi.dockerfile b/frameworks/Python/django/django-socketify-wsgi.dockerfile index 5ab6e9dcd67..017cdf7413c 100644 --- a/frameworks/Python/django/django-socketify-wsgi.dockerfile +++ b/frameworks/Python/django/django-socketify-wsgi.dockerfile @@ -1,10 +1,12 @@ -FROM python:3.10-bullseye +FROM python:3.14 ADD ./ /django WORKDIR /django -RUN apt-get update; apt-get install libuv1 -y -RUN pip install -r /django/requirements-socketify.txt + +RUN apt-get update && \ + apt-get install gcc g++ make libuv1 zlib1g -y && \ + pip install -r /django/requirements-socketify.txt EXPOSE 8080 diff --git a/frameworks/Python/django/django.dockerfile b/frameworks/Python/django/django.dockerfile index a5b5182eabf..e4502533649 100644 --- a/frameworks/Python/django/django.dockerfile +++ b/frameworks/Python/django/django.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12-bullseye +FROM python:3.14 ADD ./ /django diff --git a/frameworks/Python/django/gunicorn_conf.py b/frameworks/Python/django/gunicorn_conf.py index c6848f685b7..3334d6fef4b 100644 --- a/frameworks/Python/django/gunicorn_conf.py +++ b/frameworks/Python/django/gunicorn_conf.py @@ -1,11 +1,9 @@ import multiprocessing import os -import sys -_is_pypy = hasattr(sys, 'pypy_version_info') _is_travis = os.environ.get('TRAVIS') == 'true' -workers = int(multiprocessing.cpu_count()) +workers = multiprocessing.cpu_count() if _is_travis: workers = 2 @@ -14,4 +12,5 @@ errorlog = '-' pidfile = 'gunicorn.pid' pythonpath = 'hello' -worker_class = 'sync' \ No newline at end of file +worker_class = 'gthread' +threads = 4 \ No newline at end of file diff --git a/frameworks/Python/django/hello/hello/asgi.py b/frameworks/Python/django/hello/hello/asgi.py new file mode 100644 index 00000000000..8f542d607b7 --- /dev/null +++ b/frameworks/Python/django/hello/hello/asgi.py @@ -0,0 +1,7 @@ +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hello.settings") + +from django.core.asgi import get_asgi_application + +application = get_asgi_application() diff --git a/frameworks/Python/django/hello/hello/settings.py b/frameworks/Python/django/hello/hello/settings.py index fac79954d14..2003688f69b 100644 --- a/frameworks/Python/django/hello/hello/settings.py +++ b/frameworks/Python/django/hello/hello/settings.py @@ -2,66 +2,69 @@ DEBUG = False -SECRET_KEY = '_7mb6#v4yf@qhc(r(zbyh&z_iby-na*7wz&-v6pohsul-d#y5f' +SECRET_KEY = "_7mb6#v4yf@qhc(r(zbyh&z_iby-na*7wz&-v6pohsul-d#y5f" ADMINS = () MANAGERS = ADMINS -_django_db = os.getenv('DJANGO_DB', "") +_django_db = os.getenv("DJANGO_DB", "") DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.' + _django_db, # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': 'hello_world', # Or path to database file if using sqlite3. - 'USER': 'benchmarkdbuser', # Not used with sqlite3. - 'PASSWORD': 'benchmarkdbpass', # Not used with sqlite3. - 'HOST': 'tfb-database', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. - 'CONN_MAX_AGE': 30, + "default": { + "ENGINE": "django.db.backends." + _django_db, + "NAME": "hello_world", + "USER": "benchmarkdbuser", + "PASSWORD": "benchmarkdbpass", + "HOST": "tfb-database", + "PORT": "", + "CONN_MAX_AGE": None, # Persistent connections per worker } } if not _django_db: - DATABASES = { } + DATABASES = {} -TIME_ZONE = 'America/Chicago' -LANGUAGE_CODE = 'en-us' +TIME_ZONE = "America/Chicago" +LANGUAGE_CODE = "en-us" USE_I18N = False USE_L10N = False USE_TZ = False -MEDIA_ROOT = '' -MEDIA_URL = '' -STATIC_ROOT = '' -STATIC_URL = '/static/' +MEDIA_ROOT = "" +MEDIA_URL = "" +STATIC_ROOT = "" +STATIC_URL = "/static/" STATICFILES_DIRS = () STATICFILES_FINDERS = () MIDDLEWARE = () -ROOT_URLCONF = 'hello.urls' -WSGI_APPLICATION = 'hello.wsgi.application' +ROOT_URLCONF = "hello.urls" +WSGI_APPLICATION = "hello.wsgi.application" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': {}, + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": False, + "OPTIONS": { + "loaders": [ + ("django.template.loaders.cached.Loader", [ + "django.template.loaders.app_directories.Loader", + ]), + ], + }, }, ] INSTALLED_APPS = ( - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'world', + "world", ) LOGGING = { - 'version': 1, - 'disable_existing_loggers': True, - 'handlers': {}, - 'loggers': {}, - + "version": 1, + "disable_existing_loggers": True, + "handlers": {}, + "loggers": {}, } -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ["*"] diff --git a/frameworks/Python/django/hello/hello/urls.py b/frameworks/Python/django/hello/hello/urls.py index fbf2fbbfa97..d622f3414d8 100644 --- a/frameworks/Python/django/hello/hello/urls.py +++ b/frameworks/Python/django/hello/hello/urls.py @@ -1,11 +1,11 @@ -from django.conf.urls import url +from django.urls import path from world.views import plaintext, json, db, dbs, fortunes, update urlpatterns = [ - url(r'^plaintext$', plaintext), - url(r'^json$', json), - url(r'^db$', db), - url(r'^dbs$', dbs), - url(r'^fortunes$', fortunes), - url(r'^update$', update), + path("plaintext", plaintext), + path("json", json), + path("db", db), + path("dbs", dbs), + path("fortunes", fortunes), + path("update", update), ] diff --git a/frameworks/Python/django/hello/hello/wsgi.py b/frameworks/Python/django/hello/hello/wsgi.py index 717367e2872..1febb6fdb65 100644 --- a/frameworks/Python/django/hello/hello/wsgi.py +++ b/frameworks/Python/django/hello/hello/wsgi.py @@ -1,21 +1,7 @@ -""" -WSGI config for hello project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hello.settings") from django.core.wsgi import get_wsgi_application + application = get_wsgi_application() diff --git a/frameworks/Python/django/hello/world/models.py b/frameworks/Python/django/hello/world/models.py index 4756e2b06cd..a243e8bb47a 100644 --- a/frameworks/Python/django/hello/world/models.py +++ b/frameworks/Python/django/hello/world/models.py @@ -5,11 +5,11 @@ class World(models.Model): randomnumber = models.IntegerField() class Meta: - db_table = 'world' + db_table = "world" class Fortune(models.Model): message = models.CharField(max_length=65535) class Meta: - db_table = 'fortune' + db_table = "fortune" diff --git a/frameworks/Python/django/hello/world/views.py b/frameworks/Python/django/hello/world/views.py index 5dd6a35f35f..4d5c11c60ef 100644 --- a/frameworks/Python/django/hello/world/views.py +++ b/frameworks/Python/django/hello/world/views.py @@ -1,8 +1,9 @@ import random from operator import itemgetter from functools import partial -from ujson import dumps as uj_dumps +from orjson import dumps +from django.db import connection from django.http import HttpResponse from django.shortcuts import render @@ -14,7 +15,7 @@ def _get_queries(request): try: - queries = int(request.GET.get('queries', 1)) + queries = int(request.GET.get("queries", 1)) except Exception: queries = 1 if queries < 1: @@ -30,47 +31,54 @@ def plaintext(request): def json(request): return HttpResponse( - uj_dumps({"message": "Hello, World!"}), - content_type="application/json" - ) + dumps({"message": "Hello, World!"}), content_type="application/json" + ) def db(request): r = _random_int() - world = uj_dumps({ - 'id': r, - 'randomNumber': World.objects.get(id=r).randomnumber - }) - return HttpResponse(world, content_type="application/json") + row = World.objects.values_list('id', 'randomnumber').get(id=r) + return HttpResponse(dumps({"id": row[0], "randomNumber": row[1]}), content_type="application/json") def dbs(request): queries = _get_queries(request) + result = [] - def caller(input_): - int_ = _random_int() - return {'id': int_, 'randomNumber': World.objects.get(id=int_).randomnumber} - worlds = tuple(map(caller, range(queries))) + for _ in range(queries): + r = _random_int() + row = World.objects.values_list('id', 'randomnumber').get(id=r) + result.append({"id": row[0], "randomNumber": row[1]}) - return HttpResponse(uj_dumps(worlds), content_type="application/json") + return HttpResponse(dumps(result), content_type="application/json") def fortunes(request): - fortunes = list(Fortune.objects.values('id', 'message')) - fortunes.append({"id": 0, 'message': "Additional fortune added at request time."}) - fortunes.sort(key=itemgetter('message')) + fortunes = list(Fortune.objects.values("id", "message")) + fortunes.append({"id": 0, "message": "Additional fortune added at request time."}) + fortunes.sort(key=itemgetter("message")) - return render(request, 'fortunes.html', {'fortunes': fortunes}) + return render(request, "fortunes.html", {"fortunes": fortunes}) def update(request): queries = _get_queries(request) + result = [] + updates = [] + + + for _ in range(queries): + r = _random_int() + World.objects.values_list('id', 'randomnumber').get(id=r) # Required read + new_number = _random_int() + result.append({"id": r, "randomNumber": new_number}) + updates.append((new_number, r)) + + # Batch update using raw SQL executemany + with connection.cursor() as cursor: + cursor.executemany( + "UPDATE world SET randomnumber = %s WHERE id = %s", + updates + ) - def caller(input_): - w = World.objects.get(id=_random_int()) - w.randomnumber = _random_int() - w.save() - return {'id': w.id, 'randomNumber': w.randomnumber} - worlds = tuple(map(caller, range(queries))) - - return HttpResponse(uj_dumps(worlds), content_type="application/json") + return HttpResponse(dumps(result), content_type="application/json") diff --git a/frameworks/Python/django/requirements-granian.txt b/frameworks/Python/django/requirements-granian.txt new file mode 100644 index 00000000000..76fdae439bb --- /dev/null +++ b/frameworks/Python/django/requirements-granian.txt @@ -0,0 +1,2 @@ +-r requirements.txt +granian[uvloop]>=2.6.0,<2.7.0 diff --git a/frameworks/Python/django/requirements-gunicorn.txt b/frameworks/Python/django/requirements-gunicorn.txt index 7ec2e47c136..f8b27a2df56 100644 --- a/frameworks/Python/django/requirements-gunicorn.txt +++ b/frameworks/Python/django/requirements-gunicorn.txt @@ -1,4 +1,2 @@ -r requirements.txt -greenlet==3.1.1 -gunicorn==21.2.0 -gevent==24.10.2 \ No newline at end of file +gunicorn==23.0.0 \ No newline at end of file diff --git a/frameworks/Python/django/requirements-socketify.txt b/frameworks/Python/django/requirements-socketify.txt index ac0f1380aa1..6807c787fde 100644 --- a/frameworks/Python/django/requirements-socketify.txt +++ b/frameworks/Python/django/requirements-socketify.txt @@ -1,2 +1,2 @@ -r requirements.txt -git+https://github.com/cirospaciari/socketify.py.git@main#socketify +https://github.com/cirospaciari/socketify.py/archive/refs/heads/main.zip#egg=socketify diff --git a/frameworks/Python/django/requirements.txt b/frameworks/Python/django/requirements.txt index c7765c2c549..e630c1c8fdc 100644 --- a/frameworks/Python/django/requirements.txt +++ b/frameworks/Python/django/requirements.txt @@ -1,5 +1,5 @@ -Django==3.2.25 -mysqlclient==2.2.6 -psycopg2==2.9.9; implementation_name=='cpython' -pytz==2023.2 -ujson==5.8.0 +Django==6.0.3 +mysqlclient==2.2.7 +psycopg2-binary==2.9.11 +pytz==2025.2 +orjson==3.11.3 \ No newline at end of file diff --git a/frameworks/Python/emmett55/app.py b/frameworks/Python/emmett55/app.py index d24f7e98d62..6339a86ea36 100644 --- a/frameworks/Python/emmett55/app.py +++ b/frameworks/Python/emmett55/app.py @@ -76,7 +76,6 @@ async def pipe(self, next_pipe, **kwargs): SQL_SELECT = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' SQL_UPDATE = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ROW_ADD = [0, 'Additional fortune added at request time.'] sort_key = itemgetter(1) @@ -115,7 +114,7 @@ async def get_random_worlds(db): @app.route(pipeline=[TemplatePipe("fortunes.html"), db_ext.pipe]) async def fortunes(db): fortunes = await db.fetch('SELECT * FROM Fortune') - fortunes.append(ROW_ADD) + fortunes.append([0, "Additional fortune added at request time."]) fortunes.sort(key=sort_key) return {"fortunes": fortunes} diff --git a/frameworks/Python/eve/requirements.txt b/frameworks/Python/eve/requirements.txt index 089a0d0836c..f982e3becf5 100644 --- a/frameworks/Python/eve/requirements.txt +++ b/frameworks/Python/eve/requirements.txt @@ -5,4 +5,4 @@ gunicorn==19.9.0 itsdangerous==0.24 meinheld==1.0.2 uWSGI==2.0.22 -Werkzeug==3.1.4 +Werkzeug==3.1.6 diff --git a/frameworks/Python/falcon/app.py b/frameworks/Python/falcon/app.py index ae8561b85cb..b8dbe5e00ee 100755 --- a/frameworks/Python/falcon/app.py +++ b/frameworks/Python/falcon/app.py @@ -168,12 +168,12 @@ def run_app(): response_add_date = True bjoern.run(app, host=opt.host, port=opt.port, reuse_port=True) - if opt.server == 'fastwsgi': - import fastwsgi - response_server = "FastWSGI" + if opt.server == 'fastpysgi': + import fastpysgi + response_server = "FastPySGI" response_add_date = False - fastwsgi.server.backlog = 4096 - fastwsgi.run(app, host=opt.host, port=opt.port, loglevel=opt.verbose) + fastpysgi.server.backlog = 4096 + fastpysgi.run(app, host=opt.host, port=opt.port, loglevel=opt.verbose) if opt.server == 'socketify': import socketify diff --git a/frameworks/Python/falcon/benchmark_config.json b/frameworks/Python/falcon/benchmark_config.json index c5983f5c266..c38bd268845 100644 --- a/frameworks/Python/falcon/benchmark_config.json +++ b/frameworks/Python/falcon/benchmark_config.json @@ -62,25 +62,6 @@ "notes": "", "versus": "wsgi" }, - "socketify-asgi-pypy3": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "Falcon", - "language": "Python", - "flavor": "PyPy3", - "orm": "Full", - "platform": "ASGI", - "webserver": "Socketify.py", - "os": "Linux", - "database_os": "Linux", - "display_name": "Falcon [socketify.py ASGI PyPy3]", - "notes": "", - "versus": "asgi" - }, "socketify-asgi": { "json_url": "/json", "plaintext_url": "/plaintext", @@ -213,7 +194,7 @@ "notes": "", "versus": "uvicorn" }, - "fastwsgi": { + "fastpysgi": { "json_url": "/json", "db_url": "/db", "query_url": "/queries/", @@ -229,10 +210,10 @@ "flavor": "Python3", "orm": "Full", "platform": "WSGI", - "webserver": "FastWSGI", + "webserver": "FastPySGI", "os": "Linux", "database_os": "Linux", - "display_name": "Falcon [FastWSGI]", + "display_name": "Falcon [FastPySGI]", "notes": "", "versus": "wsgi" } diff --git a/frameworks/Python/falcon/config.toml b/frameworks/Python/falcon/config.toml index 3b66a9d2a99..0a7c63529b6 100644 --- a/frameworks/Python/falcon/config.toml +++ b/frameworks/Python/falcon/config.toml @@ -129,25 +129,6 @@ display.name = "Falcon [socketify.py ASGI]" notes = "cythonized" versus = "asgi" -[socketify-asgi-pypy3] -json.url = "/json" -plaintext.url = "/plaintext" -port = 8080 -approach = "Realistic" -classification = "Micro" -database = "Postgres" -framework = "Falcon" -language = "Python" -flavor = "PyPy3" -orm = "Full" -platform = "ASGI" -webserver = "Socketify.py" -os = "Linux" -database.os = "Linux" -display.name = "Falcon [socketify.py ASGI Pypy3]" -notes = "" -versus = "asgi" - [socketify-wsgi-pypy3] json.url = "/json" plaintext.url = "/plaintext" @@ -213,7 +194,7 @@ display.name = "Falcon [ASGI/Tortoise]" notes = "" versus = "uvicorn" -[fastwsgi] +[fastpysgi] json.url = "/json" db.url = "/db" query.url = "/queries/" @@ -229,9 +210,9 @@ language = "Python" flavor = "Python3" orm = "Full" platform = "WSGI" -webserver = "FastWSGI" +webserver = "FastPySGI" os = "Linux" database.os = "Linux" -display.name = "Falcon [FastWSGI]" +display.name = "Falcon [FastPySGI]" notes = "" versus = "wsgi" diff --git a/frameworks/Python/falcon/falcon-fastpysgi.dockerfile b/frameworks/Python/falcon/falcon-fastpysgi.dockerfile new file mode 100644 index 00000000000..fcf50ca660c --- /dev/null +++ b/frameworks/Python/falcon/falcon-fastpysgi.dockerfile @@ -0,0 +1,13 @@ +FROM python:3.11-bullseye + +RUN apt-get update; apt-get install libpq-dev python3-dev -y +WORKDIR /falcon +COPY ./ /falcon +RUN pip3 install -U pip +RUN pip3 install -r /falcon/requirements.txt +RUN pip3 install -r /falcon/requirements-fastpysgi.txt +RUN pip3 install -r /falcon/requirements-db-pony.txt + +EXPOSE 8080 + +CMD ["python3", "app.py", "-s", "fastpysgi"] diff --git a/frameworks/Python/falcon/falcon-fastwsgi.dockerfile b/frameworks/Python/falcon/falcon-fastwsgi.dockerfile deleted file mode 100644 index 63b7e8e4a75..00000000000 --- a/frameworks/Python/falcon/falcon-fastwsgi.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM python:3.11-bullseye - -RUN apt-get update; apt-get install libpq-dev python3-dev -y -WORKDIR /falcon -COPY ./ /falcon -RUN pip3 install -U pip -RUN pip3 install -r /falcon/requirements.txt -RUN pip3 install -r /falcon/requirements-fastwsgi.txt -RUN pip3 install -r /falcon/requirements-db-pony.txt - -EXPOSE 8080 - -CMD ["python3", "app.py", "-s", "fastwsgi"] diff --git a/frameworks/Python/falcon/falcon-socketify-asgi-pypy3.dockerfile b/frameworks/Python/falcon/falcon-socketify-asgi-pypy3.dockerfile deleted file mode 100644 index 9f04121efa6..00000000000 --- a/frameworks/Python/falcon/falcon-socketify-asgi-pypy3.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM pypy:3.9-bullseye - -RUN apt-get update; apt-get install libpq-dev python3-dev libuv1-dev -y -COPY ./ /falcon -WORKDIR /falcon -RUN pip3 install -U pip -RUN pip3 install -r /falcon/requirements.txt -RUN pip3 install -r /falcon/requirements-socketify.txt - -EXPOSE 8080 - -CMD python app-socketify-asgi.py diff --git a/frameworks/Python/falcon/requirements-fastpysgi.txt b/frameworks/Python/falcon/requirements-fastpysgi.txt new file mode 100644 index 00000000000..2189b52fcbd --- /dev/null +++ b/frameworks/Python/falcon/requirements-fastpysgi.txt @@ -0,0 +1 @@ +fastpysgi==0.3 diff --git a/frameworks/Python/falcon/requirements-fastwsgi.txt b/frameworks/Python/falcon/requirements-fastwsgi.txt deleted file mode 100644 index 0872c4856e0..00000000000 --- a/frameworks/Python/falcon/requirements-fastwsgi.txt +++ /dev/null @@ -1,2 +0,0 @@ -click==8.0.1 -fastwsgi==0.0.9 diff --git a/frameworks/Python/falcon/requirements-socketify-pypy.txt b/frameworks/Python/falcon/requirements-socketify-pypy.txt index 9f5ba55adf9..d7af3e22a65 100644 --- a/frameworks/Python/falcon/requirements-socketify-pypy.txt +++ b/frameworks/Python/falcon/requirements-socketify-pypy.txt @@ -1 +1 @@ -git+https://github.com/cirospaciari/socketify.py.git@main#socketify +https://github.com/cirospaciari/socketify.py/archive/refs/heads/main.zip#egg=socketify diff --git a/frameworks/Python/falcon/requirements-socketify.txt b/frameworks/Python/falcon/requirements-socketify.txt index 9f5ba55adf9..d7af3e22a65 100644 --- a/frameworks/Python/falcon/requirements-socketify.txt +++ b/frameworks/Python/falcon/requirements-socketify.txt @@ -1 +1 @@ -git+https://github.com/cirospaciari/socketify.py.git@main#socketify +https://github.com/cirospaciari/socketify.py/archive/refs/heads/main.zip#egg=socketify diff --git a/frameworks/Python/fastapi/README.md b/frameworks/Python/fastapi/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Python/fastapi/app-socketify-asgi.py b/frameworks/Python/fastapi/app-socketify-asgi.py deleted file mode 100755 index 4cb8c17de3f..00000000000 --- a/frameworks/Python/fastapi/app-socketify-asgi.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import multiprocessing -import logging -from fastapi import FastAPI, Request -from fastapi.responses import PlainTextResponse -from socketify import ASGI - - -try: - import orjson - from fastapi.responses import ORJSONResponse as JSONResponse -except ImportError: - from fastapi.responses import JSONResponse as JSONResponse - -app = FastAPI() - -@app.get("/json") -async def json_serialization(): - return JSONResponse({"message": "Hello, world!"}) - -@app.get("/plaintext") -async def plaintext(): - return PlainTextResponse(b"Hello, world!") - - -_is_travis = os.environ.get('TRAVIS') == 'true' - -workers = int(multiprocessing.cpu_count()) -if _is_travis: - workers = 2 - -def run_app(): - ASGI(app).listen(8080, lambda config: logging.info(f"Listening on port http://localhost:{config.port} now\n")).run() - - -def create_fork(): - n = os.fork() - # n greater than 0 means parent process - if not n > 0: - run_app() - - -# fork limiting the cpu count - 1 -for i in range(1, workers): - create_fork() - -run_app() # run app on the main process too :) \ No newline at end of file diff --git a/frameworks/Python/fastapi/app.py b/frameworks/Python/fastapi/app.py old mode 100755 new mode 100644 index ef2e10c1082..5d7ec97d550 --- a/frameworks/Python/fastapi/app.py +++ b/frameworks/Python/fastapi/app.py @@ -1,15 +1,20 @@ import multiprocessing from contextlib import asynccontextmanager -import asyncpg +try: + import asyncpg + _DB_ALLOWED = True +except ImportError: + _DB_ALLOWED = False + import os from fastapi import FastAPI, Request from fastapi.responses import PlainTextResponse -try: +if os.getenv('USE_ORJSON', "0") == "1": import orjson from fastapi.responses import ORJSONResponse as JSONResponse -except ImportError: +else: from fastapi.responses import UJSONResponse as JSONResponse from fastapi.templating import Jinja2Templates @@ -17,7 +22,6 @@ READ_ROW_SQL = 'SELECT "id", "randomnumber" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, "Additional fortune added at request time."] MAX_POOL_SIZE = 1000//multiprocessing.cpu_count() MIN_POOL_SIZE = max(int(MAX_POOL_SIZE / 2), 1) @@ -35,8 +39,6 @@ def get_num_queries(queries): return query_count -connection_pool = None - templates = Jinja2Templates(directory="templates") @@ -61,7 +63,7 @@ async def lifespan(app: FastAPI): await app.state.connection_pool.close() -app = FastAPI(lifespan=lifespan) +app = FastAPI(lifespan=lifespan) if _DB_ALLOWED else FastAPI() @app.get("/json") @@ -98,7 +100,7 @@ async def fortunes(request: Request): async with app.state.connection_pool.acquire() as connection: fortunes = await connection.fetch("SELECT * FROM Fortune") - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, "Additional fortune added at request time."]) fortunes.sort(key=lambda row: row[1]) return templates.TemplateResponse("fortune.html", {"fortunes": fortunes, "request": request}) diff --git a/frameworks/Python/fastapi/app_orm.py b/frameworks/Python/fastapi/app_orm.py old mode 100755 new mode 100644 index 04ae60753ac..7759beb01e6 --- a/frameworks/Python/fastapi/app_orm.py +++ b/frameworks/Python/fastapi/app_orm.py @@ -43,9 +43,8 @@ class Fortune(Base): ADDITIONAL_FORTUNE = Fortune( id=0, message="Additional fortune added at request time." ) -MAX_POOL_SIZE = 1000//multiprocessing.cpu_count() - sort_fortunes_key = attrgetter("message") +MAX_POOL_SIZE = 1000//(multiprocessing.cpu_count()*2) template_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), "templates" diff --git a/frameworks/Python/fastapi/app_server.py b/frameworks/Python/fastapi/app_server.py new file mode 100644 index 00000000000..f9189d68074 --- /dev/null +++ b/frameworks/Python/fastapi/app_server.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +import os +import sys +import fastapi + +from app import app + +if __name__ == "__main__": + import optparse + import multiprocessing + import logging + + parser = optparse.OptionParser("usage: %prog [options]", add_help_option=False) + parser.add_option("-h", "--host", dest="host", default='0.0.0.0', type="string") + parser.add_option("-p", "--port", dest="port", default=8080, type="int") + parser.add_option("-s", "--server", dest="server", default="", type="string") + parser.add_option("-w", "--workers", dest="workers", default=0, type="int") + parser.add_option("-k", "--keepalive", dest="keepalive", default=60, type="int") + parser.add_option("-v", "--verbose", dest="verbose", default=0, type="int") + (opt, args) = parser.parse_args() + + _is_travis = os.environ.get('TRAVIS') == 'true' + + workers = opt.workers + if workers <= 0: + workers = int(multiprocessing.cpu_count()) + + if _is_travis: + workers = 2 + + def run_app(): + if opt.server in [ 'si', 'socketify' ]: + import socketify + siapp = socketify.ASGI(app) + siapp.listen(opt.port, lambda config: logging.info(f"Listening on port http://localhost:{opt.port} now\n")) + siapp.run() + return + + if opt.server in [ 'fp', 'fastpysgi' ]: + import fastpysgi + fastpysgi.server.loop_timeout = 1 + fastpysgi.server.hook_sigint = 1 + fastpysgi.server.backlog = 4096 + fastpysgi.run(app, host=opt.host, port=opt.port, loglevel=opt.verbose) + return + + raise Exception(f'Unknown server name = "{opt.server}"') + + def create_fork(): + n = os.fork() + # n greater than 0 means parent process + if not n > 0: + run_app() + + # fork limiting the cpu count - 1 + for i in range(1, workers): + create_fork() + + run_app() # run app on the main process too :) diff --git a/frameworks/Python/fastapi/benchmark_config.json b/frameworks/Python/fastapi/benchmark_config.json old mode 100755 new mode 100644 index 6fbceb1f0ae..18d842a7f07 --- a/frameworks/Python/fastapi/benchmark_config.json +++ b/frameworks/Python/fastapi/benchmark_config.json @@ -1,6 +1,7 @@ { "framework": "fastapi", - "tests": [{ + "tests": [ + { "default": { "json_url": "/json", "fortune_url": "/fortunes", @@ -62,27 +63,6 @@ "notes": "", "versus": "None" }, - "gunicorn-orjson": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "FastAPI", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "FastAPI-gunicorn-orjson", - "notes": "", - "versus": "None" - }, "gunicorn-orm": { "fortune_url": "/fortunes", "db_url": "/db", @@ -127,28 +107,7 @@ "notes": "", "versus": "None" }, - "hypercorn-orjson": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "FastAPI", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Hypercorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "FastAPI-hypercorn-orjson", - "notes": "", - "versus": "None" - }, - "nginx-unit": { + "nginx": { "json_url": "/json", "fortune_url": "/fortunes", "plaintext_url": "/plaintext", @@ -164,35 +123,12 @@ "flavor": "Python3", "orm": "Raw", "platform": "asyncio", - "webserver": "nginx-unit", - "os": "Linux", - "database_os": "Linux", - "display_name": "FastAPI-nginx-unit", - "notes": "", - "versus": "None", - "tags": ["broken"] - }, - "nginx-unit-orjson": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "FastAPI", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "nginx-unit", + "webserver": "nginx", "os": "Linux", "database_os": "Linux", - "display_name": "FastAPI-nginx-unit-orjson", + "display_name": "FastAPI-gnuicorn-nginx", "notes": "", - "versus": "None", - "tags": ["broken"] + "versus": "None" }, "uvicorn": { "json_url": "/json", @@ -217,8 +153,10 @@ "notes": "", "versus": "None" }, - "uvicorn-orjson": { + "fastpysgi": { "json_url": "/json", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -231,12 +169,13 @@ "flavor": "Python3", "orm": "Raw", "platform": "asyncio", - "webserver": "Uvicorn", + "webserver": "FastPySGI", "os": "Linux", "database_os": "Linux", - "display_name": "FastAPI-uvicorn-orjson", + "display_name": "FastAPI [FastPySGI]", "notes": "", - "versus": "None" + "versus": "fastapi" } - }] + } + ] } diff --git a/frameworks/Python/fastapi/config.toml b/frameworks/Python/fastapi/config.toml index 8d33cd249ad..44e47e8d81a 100644 --- a/frameworks/Python/fastapi/config.toml +++ b/frameworks/Python/fastapi/config.toml @@ -44,24 +44,6 @@ platform = "None" webserver = "Socketify.py" versus = "None" -[gunicorn-orjson] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "Gunicorn" -versus = "None" - - [gunicorn-orm] urls.plaintext = "/plaintext" urls.json = "/json" @@ -96,42 +78,7 @@ platform = "None" webserver = "Hypercorn" versus = "None" - -[hypercorn-orjson] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "Hypercorn" -versus = "None" - -[nginx-unit] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "nginx-unit" -versus = "None" - -[nginx-unit-orjson] +[nginx] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -145,10 +92,9 @@ database_os = "Linux" os = "Linux" orm = "Raw" platform = "None" -webserver = "nginx-unit" +webserver = "nginx" versus = "None" - [uvicorn] urls.plaintext = "/plaintext" urls.json = "/json" @@ -166,7 +112,7 @@ platform = "None" webserver = "uvicorn" versus = "None" -[uvicorn-orjson] +[fastpysgi] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -180,5 +126,5 @@ database_os = "Linux" os = "Linux" orm = "Raw" platform = "None" -webserver = "uvicorn" -versus = "None" +webserver = "nginx" +versus = "fastapi" diff --git a/frameworks/Python/fastapi/fastapi-fastpysgi.dockerfile b/frameworks/Python/fastapi/fastapi-fastpysgi.dockerfile new file mode 100644 index 00000000000..45403f2ddad --- /dev/null +++ b/frameworks/Python/fastapi/fastapi-fastpysgi.dockerfile @@ -0,0 +1,17 @@ +FROM python:3.14-bookworm + +WORKDIR /fastapi + +RUN python -m venv /opt/venv +ENV PATH="/opt/venv/bin:$PATH" + +RUN apt-get install -y --no-install-recommends libpq-dev +RUN rm -rf /var/lib/apt/lists/* + +COPY . ./ + +RUN pip install -r requirements-fastpysgi.txt + +EXPOSE 8080 + +CMD python app_server.py -s fastpysgi diff --git a/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile deleted file mode 100644 index 4f0712849e5..00000000000 --- a/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:3.13 - -WORKDIR /fastapi - -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-orjson.txt requirements-gunicorn.txt requirements-uvicorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-orjson.txt -r requirements-gunicorn.txt -r requirements-uvicorn.txt - -COPY . ./ - -EXPOSE 8080 - -CMD gunicorn app:app -k uvicorn.workers.UvicornWorker -c fastapi_conf.py diff --git a/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile b/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile index 64dab70e99b..b835a0b52aa 100644 --- a/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile +++ b/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile @@ -1,18 +1,16 @@ -FROM python:3.13 +FROM python:3.14 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-sqlalchemy.txt requirements-gunicorn.txt requirements-uvicorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-sqlalchemy.txt -r requirements-gunicorn.txt -r requirements-uvicorn.txt +RUN pip3 install cython==3.2.3 COPY . ./ +RUN pip3 install -r requirements-sqlalchemy.txt + EXPOSE 8080 ENV CONNECTION=ORM diff --git a/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile deleted file mode 100644 index fc50bd7ddae..00000000000 --- a/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:3.13 - -WORKDIR /fastapi - -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-orjson.txt requirements-hypercorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-orjson.txt -r requirements-hypercorn.txt - -COPY . ./ - -EXPOSE 8080 - -CMD hypercorn app:app --bind 0.0.0.0:8080 --workers $(nproc) diff --git a/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile b/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile index 58f2d166d12..c8268ad85de 100644 --- a/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile +++ b/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile @@ -1,18 +1,16 @@ -FROM python:3.13 +FROM python:3.14 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-hypercorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-hypercorn.txt +RUN pip3 install cython==3.2.3 COPY . ./ +RUN pip3 install -r requirements-hypercorn.txt + EXPOSE 8080 CMD hypercorn app:app --bind 0.0.0.0:8080 --workers $(nproc) diff --git a/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile deleted file mode 100644 index af3ed2bd75d..00000000000 --- a/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM nginx/unit:1.29.1-python3.13 - -WORKDIR /fastapi - -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-orjson.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-orjson.txt - -COPY . ./ - -COPY ./nginx-unit-config-orjson.sh /docker-entrypoint.d/ - -ENV PGSSLMODE disable - -EXPOSE 8080 diff --git a/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile b/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile deleted file mode 100644 index 261c84d5520..00000000000 --- a/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM nginx/unit:1.29.1-python3.13 - -WORKDIR /fastapi - -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -RUN pip3 install cython==3.0.12 - -COPY requirements.txt ./ - -RUN pip3 install -r requirements.txt - -COPY . ./ - -COPY ./nginx-unit-config.sh /docker-entrypoint.d/ - -ENV PGSSLMODE disable - -EXPOSE 8080 diff --git a/frameworks/Python/fastapi/fastapi-nginx.dockerfile b/frameworks/Python/fastapi/fastapi-nginx.dockerfile new file mode 100644 index 00000000000..fa5d4e6a794 --- /dev/null +++ b/frameworks/Python/fastapi/fastapi-nginx.dockerfile @@ -0,0 +1,21 @@ +FROM python:3.14 + +WORKDIR /fastapi + +RUN apt update +RUN apt install nginx -y +RUN python -m venv /opt/venv +ENV PATH="/opt/venv/bin:$PATH" + +RUN pip3 install cython==3.2.3 + +COPY . ./ + +RUN pip3 install -r requirements-gunicorn.txt + +ENV PGSSLMODE disable + +EXPOSE 8080 + +RUN chmod +x /fastapi/nginx-entrypoint.sh +ENTRYPOINT ["/fastapi/nginx-entrypoint.sh"] diff --git a/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile b/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile index 39a7e0c5b05..5ba8817e223 100644 --- a/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile +++ b/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile @@ -5,12 +5,12 @@ WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -COPY requirements-socketify-pypy.txt ./ RUN apt-get update; apt-get install libuv1 -y -RUN pip3 install -r requirements-socketify-pypy.txt COPY . ./ +RUN pip3 install -r requirements-socketify-pypy.txt + EXPOSE 8080 -CMD python ./app-socketify-asgi.py +CMD python app_server.py -s socketify diff --git a/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile b/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile index 58c39a397cd..b991eb53188 100644 --- a/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile +++ b/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.13-bullseye +FROM python:3.14 WORKDIR /fastapi @@ -6,14 +6,14 @@ RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" RUN apt-get update; apt-get install libuv1 -y -RUN pip3 install cython==3.0.12 +RUN pip3 install cython==3.2.3 -COPY requirements-socketify.txt ./ +COPY . ./ RUN pip3 install -r requirements-socketify.txt -COPY . ./ - EXPOSE 8080 -CMD python ./app-socketify-asgi.py +ENV USE_ORJSON=1 + +CMD python app_server.py -s socketify diff --git a/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile deleted file mode 100644 index 59a6e040cd0..00000000000 --- a/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:3.13 - -WORKDIR /fastapi - -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-orjson.txt requirements-uvicorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-orjson.txt -r requirements-uvicorn.txt - -COPY . ./ - -EXPOSE 8080 - -CMD uvicorn app:app --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level error --no-access-log --no-proxy-headers diff --git a/frameworks/Python/fastapi/fastapi-uvicorn.dockerfile b/frameworks/Python/fastapi/fastapi-uvicorn.dockerfile index 115104e3e49..65440057a24 100644 --- a/frameworks/Python/fastapi/fastapi-uvicorn.dockerfile +++ b/frameworks/Python/fastapi/fastapi-uvicorn.dockerfile @@ -1,18 +1,16 @@ -FROM python:3.13 +FROM python:3.14 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-uvicorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-uvicorn.txt +RUN pip3 install cython==3.2.3 COPY . ./ +RUN pip3 install -r requirements-uvicorn.txt + EXPOSE 8080 CMD uvicorn app:app --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level error --no-access-log --no-proxy-headers diff --git a/frameworks/Python/fastapi/fastapi.dockerfile b/frameworks/Python/fastapi/fastapi.dockerfile index 7208575d191..b3b9b6a6bcc 100644 --- a/frameworks/Python/fastapi/fastapi.dockerfile +++ b/frameworks/Python/fastapi/fastapi.dockerfile @@ -1,18 +1,16 @@ -FROM python:3.13 +FROM python:3.14 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==3.0.12 - -COPY requirements.txt requirements-gunicorn.txt requirements-uvicorn.txt ./ - -RUN pip3 install -r requirements.txt -r requirements-gunicorn.txt -r requirements-uvicorn.txt +RUN pip3 install cython==3.2.3 COPY . ./ +RUN pip3 install -r requirements-gunicorn.txt + EXPOSE 8080 CMD gunicorn app:app -k uvicorn.workers.UvicornWorker -c fastapi_conf.py diff --git a/frameworks/Python/fastapi/nginx-entrypoint.sh b/frameworks/Python/fastapi/nginx-entrypoint.sh new file mode 100644 index 00000000000..e294f88cf1b --- /dev/null +++ b/frameworks/Python/fastapi/nginx-entrypoint.sh @@ -0,0 +1,42 @@ +#!/bin/sh +set -e +gunicorn app:app -k uvicorn.workers.UvicornWorker -c fastapi_conf.py + +cat > /fastapi/nginx.conf <> /fastapi/nginx.conf < Template: async with app.state.connection_pool.acquire() as connection: fortunes = await connection.fetch("SELECT * FROM Fortune") - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, 'Additional fortune added at request time.']) fortunes.sort(key=lambda row: row[1]) return Template( "fortune.html", diff --git a/frameworks/Python/litestar/app_orm.py b/frameworks/Python/litestar/app_orm.py old mode 100755 new mode 100644 diff --git a/frameworks/Python/litestar/benchmark_config.json b/frameworks/Python/litestar/benchmark_config.json old mode 100755 new mode 100644 index 1f94fc49174..3158871dae0 --- a/frameworks/Python/litestar/benchmark_config.json +++ b/frameworks/Python/litestar/benchmark_config.json @@ -110,9 +110,7 @@ "versus": "None" }, "granian-orm": { - "json_url": "/json", "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", diff --git a/frameworks/Python/litestar/requirements-granian.txt b/frameworks/Python/litestar/requirements-granian.txt index 946bfa8d0b1..61939968640 100644 --- a/frameworks/Python/litestar/requirements-granian.txt +++ b/frameworks/Python/litestar/requirements-granian.txt @@ -1,2 +1,2 @@ -granian==2.3.1 -litestar-granian==0.13.0 \ No newline at end of file +granian==2.5.0 +litestar-granian==0.14.2 diff --git a/frameworks/Python/litestar/requirements-gunicorn.txt b/frameworks/Python/litestar/requirements-gunicorn.txt index c95d2c0209a..9f4c0c7d266 100644 --- a/frameworks/Python/litestar/requirements-gunicorn.txt +++ b/frameworks/Python/litestar/requirements-gunicorn.txt @@ -1,2 +1,2 @@ gunicorn==23.0.0 -uvicorn-worker==0.3.0 +uvicorn-worker==0.4.0 diff --git a/frameworks/Python/litestar/requirements-socketify.txt b/frameworks/Python/litestar/requirements-socketify.txt index 75fdf6fc3dd..6dafde7366e 100644 --- a/frameworks/Python/litestar/requirements-socketify.txt +++ b/frameworks/Python/litestar/requirements-socketify.txt @@ -1,3 +1,4 @@ -orjson==3.10.16 -litestar==2.17.0 -git+https://github.com/cirospaciari/socketify.py.git@main#socketify +orjson==3.11.6 +litestar==2.18.0 +sniffio==1.3.0 +https://github.com/cirospaciari/socketify.py/archive/refs/heads/main.zip#egg=socketify diff --git a/frameworks/Python/litestar/requirements-sqlalchemy.txt b/frameworks/Python/litestar/requirements-sqlalchemy.txt index d2e7a36be45..af253605964 100644 --- a/frameworks/Python/litestar/requirements-sqlalchemy.txt +++ b/frameworks/Python/litestar/requirements-sqlalchemy.txt @@ -1,3 +1,3 @@ psycopg2==2.9.10 SQLAlchemy==2.0.40 -litestar[sqlalchemy]==2.16.0 \ No newline at end of file +litestar[sqlalchemy]==2.18.0 diff --git a/frameworks/Python/litestar/requirements-uvicorn.txt b/frameworks/Python/litestar/requirements-uvicorn.txt index e9603a4a89c..3e302bf58de 100644 --- a/frameworks/Python/litestar/requirements-uvicorn.txt +++ b/frameworks/Python/litestar/requirements-uvicorn.txt @@ -1,3 +1,3 @@ -uvicorn==0.34.2 -uvloop==0.21.0 +uvicorn==0.38.0 +uvloop==0.22.1 httptools==0.6.4 diff --git a/frameworks/Python/litestar/requirements.txt b/frameworks/Python/litestar/requirements.txt index f45f8fd344d..2defd23212c 100644 --- a/frameworks/Python/litestar/requirements.txt +++ b/frameworks/Python/litestar/requirements.txt @@ -1,4 +1,5 @@ -asyncpg==0.30.0 -litestar==2.17.0 +asyncpg==0.31.0 +litestar==2.18.0 Jinja2==3.1.6 -orjson==3.10.18 \ No newline at end of file +orjson==3.11.6 +sniffio==1.3.0 diff --git a/frameworks/Python/microdot/app_raw.py b/frameworks/Python/microdot/app_raw.py index 9aa8a7ab362..b0e50fd52f4 100644 --- a/frameworks/Python/microdot/app_raw.py +++ b/frameworks/Python/microdot/app_raw.py @@ -50,11 +50,6 @@ def generate_ids(num_queries): return sample(range(1, 10001), num_queries) -@app.route("/json") -async def test_json(request): - return {"message": "Hello, World!"} - - @app.route("/db") async def test_db(request): id = randint(1, 10000) @@ -107,11 +102,6 @@ async def test_updates(request): return worlds -@app.route("/plaintext") -async def test_plaintext(request): - return b"Hello, World!" - - @cached(cache={}, key=lambda stmt, id: hashkey(id)) async def get_cached_world(stmt, id): result = await stmt.fetchrow(id) diff --git a/frameworks/Python/microdot/benchmark_config.json b/frameworks/Python/microdot/benchmark_config.json index 712e89b44b9..dccd5b305a3 100644 --- a/frameworks/Python/microdot/benchmark_config.json +++ b/frameworks/Python/microdot/benchmark_config.json @@ -27,12 +27,10 @@ "versus": "None" }, "raw": { - "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", "cached_query_url": "/cached-queries?count=", "port": 8080, "approach": "Realistic", diff --git a/frameworks/Python/mrhttp/benchmark_config.json b/frameworks/Python/mrhttp/benchmark_config.json index 8303a252e1f..657dd8fc2b4 100644 --- a/frameworks/Python/mrhttp/benchmark_config.json +++ b/frameworks/Python/mrhttp/benchmark_config.json @@ -5,7 +5,7 @@ "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Micro", "framework": "mrhttp", "language": "Python", diff --git a/frameworks/Python/pyramid/benchmark_config.json b/frameworks/Python/pyramid/benchmark_config.json index fd575a88643..33b9fc31046 100644 --- a/frameworks/Python/pyramid/benchmark_config.json +++ b/frameworks/Python/pyramid/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "pyramid", + "maintainers": ["slav0nic"], "tests": [{ "default": { "json_url": "/json", @@ -8,6 +9,7 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "plaintext_url": "/plaintext", + "cached_query_url": "/cached-queries?count=", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -17,7 +19,7 @@ "flavor": "Python3", "orm": "Full", "platform": "None", - "webserver": "Meinheld", + "webserver": "Gunicorn", "os": "Linux", "database_os": "Linux", "display_name": "Pyramid", diff --git a/frameworks/Python/pyramid/development.ini b/frameworks/Python/pyramid/development.ini index 3613f36d0f0..4b7c970a996 100644 --- a/frameworks/Python/pyramid/development.ini +++ b/frameworks/Python/pyramid/development.ini @@ -13,7 +13,7 @@ pyramid.debug_routematch = false pyramid.default_locale_name = en pyramid.includes = pyramid_debugtoolbar debugtoolbar.active_panels = performance -sqlalchemy.url = postgresql:///frameworkbenchmarks +sqlalchemy.url = postgresql+psycopg:///frameworkbenchmarks ### # wsgi server configuration diff --git a/frameworks/Python/pyramid/frameworkbenchmarks/__init__.py b/frameworks/Python/pyramid/frameworkbenchmarks/__init__.py index 0fe6fbe2fe3..71844d11b4f 100644 --- a/frameworks/Python/pyramid/frameworkbenchmarks/__init__.py +++ b/frameworks/Python/pyramid/frameworkbenchmarks/__init__.py @@ -30,6 +30,7 @@ def main(global_config, **settings): config.add_route("test_4", "/fortunes") config.add_route("test_5", "/updates") config.add_route("test_6", "/plaintext") + config.add_route("test_7", "/cached-queries") config.set_default_csrf_options(require_csrf=False) engine = get_engine(settings) diff --git a/frameworks/Python/pyramid/frameworkbenchmarks/models.py b/frameworks/Python/pyramid/frameworkbenchmarks/models.py index b41163c1d6b..b41943e3cb4 100644 --- a/frameworks/Python/pyramid/frameworkbenchmarks/models.py +++ b/frameworks/Python/pyramid/frameworkbenchmarks/models.py @@ -15,12 +15,11 @@ def get_engine(settings): pool_size=100, max_overflow=25, enable_from_linting=False, - future=True, ) def get_session_factory(engine): - Session = sessionmaker(bind=engine, autoflush=False, future=True) + Session = sessionmaker(bind=engine, autoflush=False) return Session diff --git a/frameworks/Python/pyramid/frameworkbenchmarks/views.py b/frameworks/Python/pyramid/frameworkbenchmarks/views.py index ad6ddcdad61..46c67833a47 100644 --- a/frameworks/Python/pyramid/frameworkbenchmarks/views.py +++ b/frameworks/Python/pyramid/frameworkbenchmarks/views.py @@ -13,8 +13,8 @@ from frameworkbenchmarks.models import Fortune, World -def parse_query(request): - queries = request.GET.get("queries", 1) +def parse_query(request, param="queries"): + queries = request.GET.get(param, 1) try: queries = int(queries) except ValueError: @@ -90,6 +90,9 @@ def test_5(request): return resultset +_world_cache = {} + + @view_config(route_name="test_6") def test_6(request): """ @@ -99,3 +102,19 @@ def test_6(request): body=b"Hello, World!", content_type="text/plain", charset="utf-8" ) return response + + +@view_config(route_name="test_7", renderer="json") +def test_7(request): + """ + Test type 7: Cached queries + """ + count = parse_query(request, "count") + result = [] + for num in sample(range(1, 10001), count): + obj = _world_cache.get(num) + if obj is None: + obj = request.dbsession.get(World, num).__json__() + _world_cache[num] = obj + result.append(obj) + return result diff --git a/frameworks/Python/pyramid/gunicorn_conf.py b/frameworks/Python/pyramid/gunicorn_conf.py index 42c836f4e60..a77791e7624 100644 --- a/frameworks/Python/pyramid/gunicorn_conf.py +++ b/frameworks/Python/pyramid/gunicorn_conf.py @@ -1,21 +1,9 @@ import multiprocessing -import os - - -_is_travis = os.environ.get("TRAVIS") == "true" - -workers = multiprocessing.cpu_count() * 3 -if _is_travis: - workers = 2 +workers = multiprocessing.cpu_count() bind = "0.0.0.0:8080" keepalive = 120 errorlog = "-" +accesslog = None pidfile = "/tmp/gunicorn.pid" - -worker_class = "meinheld.gmeinheld.MeinheldWorker" - -def post_fork(server, worker): - # Disalbe access log - import meinheld.server - meinheld.server.set_access_logger(None) +worker_class = "sync" diff --git a/frameworks/Python/pyramid/production.ini b/frameworks/Python/pyramid/production.ini index c890db50932..df0a40c166c 100644 --- a/frameworks/Python/pyramid/production.ini +++ b/frameworks/Python/pyramid/production.ini @@ -11,7 +11,7 @@ pyramid.debug_authorization = false pyramid.debug_notfound = false pyramid.debug_routematch = false pyramid.default_locale_name = en -sqlalchemy.url = postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world +sqlalchemy.url = postgresql+psycopg://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world ### # wsgi server configuration ### diff --git a/frameworks/Python/pyramid/pyramid.dockerfile b/frameworks/Python/pyramid/pyramid.dockerfile index 42595febecf..02b1218a4da 100644 --- a/frameworks/Python/pyramid/pyramid.dockerfile +++ b/frameworks/Python/pyramid/pyramid.dockerfile @@ -1,9 +1,7 @@ -FROM python:3.10 +FROM python:3.14 ADD ./requirements.txt /pyramid/requirements.txt -# https://github.com/mopemope/meinheld/pull/123 -RUN pip3 install --no-deps "meinheld==1.0.2" RUN pip3 install -r /pyramid/requirements.txt ADD ./ /pyramid WORKDIR /pyramid diff --git a/frameworks/Python/pyramid/requirements.in b/frameworks/Python/pyramid/requirements.in deleted file mode 100644 index 1afc1f2f618..00000000000 --- a/frameworks/Python/pyramid/requirements.in +++ /dev/null @@ -1,5 +0,0 @@ -gunicorn -SQLAlchemy[postgresql] -pyramid -pyramid_chameleon -orjson \ No newline at end of file diff --git a/frameworks/Python/pyramid/requirements.txt b/frameworks/Python/pyramid/requirements.txt index d9cd315c6e3..d18e156b693 100644 --- a/frameworks/Python/pyramid/requirements.txt +++ b/frameworks/Python/pyramid/requirements.txt @@ -1,49 +1,6 @@ -# -# This file is autogenerated by pip-compile with python 3.9 -# To update, run: -# -# pip-compile --output-file=requirements.txt requirements.in -# -chameleon==3.9.1 - # via pyramid-chameleon -greenlet==1.1.2 - # via sqlalchemy -gunicorn==22.0.0 - # via -r requirements.in -hupper==1.10.3 - # via pyramid -orjson==3.9.15 - # via -r requirements.in -packaging==24.0 - # via gunicorn -pastedeploy==2.1.1 - # via plaster-pastedeploy -plaster==1.0 - # via - # plaster-pastedeploy - # pyramid -plaster-pastedeploy==0.7 - # via pyramid -psycopg2==2.9.2 - # via sqlalchemy -pyramid==2.0 - # via - # -r requirements.in - # pyramid-chameleon +pyramid==2.0.2 +gunicorn==25.1.0 pyramid-chameleon==0.3 - # via -r requirements.in -sqlalchemy[postgresql]==1.4.28 - # via -r requirements.in -translationstring==1.4 - # via pyramid -venusian==3.0.0 - # via pyramid -webob==1.8.7 - # via pyramid -zope-deprecation==4.4.0 - # via pyramid -zope-interface==5.4.0 - # via pyramid - -# The following packages are considered to be unsafe in a requirements file: -# setuptools +sqlalchemy[postgresql-psycopgbinary]==2.0.47 +orjson==3.11.7 +setuptools<82 # Workaround until pyramid 2.1, see: https://github.com/Pylons/pyramid/issues/3731 \ No newline at end of file diff --git a/frameworks/Python/pyvoy/README.md b/frameworks/Python/pyvoy/README.md new file mode 100644 index 00000000000..09c0dd96f63 --- /dev/null +++ b/frameworks/Python/pyvoy/README.md @@ -0,0 +1,35 @@ +# pyvoy Benchmark Test + +This is the pyvoy portion of a [benchmarking tests suite](../../) comparing a variety of web development platforms. + +The information below is specific to pyvoy. For further guidance, review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). + +Also note that there is additional information provided in the [Python README](../). + +## Description + +[pyvoy](https://github.com/curioswitch/pyvoy) is Python application server built on Envoy. + +## Test Paths & Source + +pyvoy includes three different implementations: + +- ASGI implementation in [app\_asgi.py](app_asgi.py) +- WSGI implementation in [app\_wsgi.py](app_wsgi.py) + +ASGI implementation includes the following tests: + +* JSON Serialization: "/json" +* Plaintext: "/plaintext" +* Single Database Query: "/db" +* Multiple Database Queries: "queries?queries=#" +* Fortunes: "/fortunes" +* Database Updates: "updates?queries=#" + +while WSGI implementation only include JSON Serialization and Plaintext tests. + +*Replace # with an actual number.* + +## Resources + +* [Github repository](https://github.com/curioswitch/pyvoy) diff --git a/frameworks/Python/pyvoy/app_asgi.py b/frameworks/Python/pyvoy/app_asgi.py new file mode 100644 index 00000000000..d7c7b732c27 --- /dev/null +++ b/frameworks/Python/pyvoy/app_asgi.py @@ -0,0 +1,208 @@ +import os + +from operator import itemgetter +from pathlib import Path +from random import randint, sample +from urllib.parse import parse_qs + +import asyncpg +import jinja2 +import orjson + +PG_POOL_SIZE = 4 + + +class NoResetConnection(asyncpg.Connection): + __slots__ = () + + def get_reset_query(self): + return "" + + +async def pg_setup(): + global pool + pool = await asyncpg.create_pool( + user=os.getenv('PGUSER', 'benchmarkdbuser'), + password=os.getenv('PGPASS', 'benchmarkdbpass'), + database='hello_world', + host='tfb-database', + port=5432, + min_size=PG_POOL_SIZE, + max_size=PG_POOL_SIZE, + connection_class=NoResetConnection, + ) + + +SQL_SELECT = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' +SQL_UPDATE = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' +ROW_ADD = [0, 'Additional fortune added at request time.'] + +JSON_RESPONSE = { + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + [b'content-type', b'application/json'], + ] +} +HTML_RESPONSE = { + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + [b'content-type', b'text/html; charset=utf-8'], + ] +} +PLAINTEXT_RESPONSE = { + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + [b'content-type', b'text/plain; charset=utf-8'], + ] +} + +pool = None +key = itemgetter(1) +json_dumps = orjson.dumps + +with Path('templates/fortune.html').open('r') as f: + template = jinja2.Template(f.read()) + + +def get_num_queries(scope): + try: + query_string = scope['query_string'] + query_count = int(parse_qs(query_string)[b'queries'][0]) + except (KeyError, IndexError, ValueError): + return 1 + + if query_count < 1: + return 1 + if query_count > 500: + return 500 + return query_count + + +async def route_json(scope, receive, send): + await send(JSON_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': json_dumps({'message': 'Hello, world!'}), + 'more_body': False + }) + + +async def route_db(scope, receive, send): + row_id = randint(1, 10000) + async with pool.acquire() as connection: + number = await connection.fetchval(SQL_SELECT, row_id) + + await send(JSON_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': json_dumps({'id': row_id, 'randomNumber': number}), + 'more_body': False + }) + + +async def route_queries(scope, receive, send): + num_queries = get_num_queries(scope) + row_ids = sample(range(1, 10000), num_queries) + worlds = [] + + async with pool.acquire() as connection: + rows = await connection.fetchmany(SQL_SELECT, [(v,) for v in row_ids]) + + worlds = [{'id': row_id, 'randomNumber': number[0]} for row_id, number in zip(row_ids, rows)] + await send(JSON_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': json_dumps(worlds), + 'more_body': False + }) + + +async def route_fortunes(scope, receive, send): + async with pool.acquire() as connection: + fortunes = await connection.fetch('SELECT * FROM Fortune') + + fortunes.append(ROW_ADD) + fortunes.sort(key=key) + content = template.render(fortunes=fortunes).encode('utf-8') + await send(HTML_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': content, + 'more_body': False + }) + + +async def route_updates(scope, receive, send): + num_queries = get_num_queries(scope) + updates = list(zip( + sample(range(1, 10000), num_queries), + sorted(sample(range(1, 10000), num_queries)) + )) + worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] + + async with pool.acquire() as connection: + await connection.executemany(SQL_SELECT, [(i[0],) for i in updates]) + await connection.executemany(SQL_UPDATE, updates) + + await send(JSON_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': json_dumps(worlds), + 'more_body': False + }) + + +async def route_plaintext(scope, receive, send): + await send(PLAINTEXT_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': b'Hello, world!', + 'more_body': False + }) + + +async def handle_404(scope, receive, send): + await send(PLAINTEXT_RESPONSE) + await send({ + 'type': 'http.response.body', + 'body': b'Not found', + 'more_body': False + }) + + +routes = { + '/json': route_json, + '/db': route_db, + '/queries': route_queries, + '/fortunes': route_fortunes, + '/updates': route_updates, + '/plaintext': route_plaintext +} + + +class App: + __slots__ = ["_handler"] + + def __init__(self): + self._handler = self._lifespan + + def __call__(self, scope, receive, send): + return self._handler(scope, receive, send) + + async def _lifespan(self, scope, receive, send): + if scope['type'] == 'lifespan': + message = await receive() + if message['type'] == 'lifespan.startup': + await pg_setup() + self._handler = self._asgi + await send({'type': 'lifespan.startup.complete'}) + + def _asgi(self, scope, receive, send): + handler = routes.get(scope['path'], handle_404) + return handler(scope, receive, send) + + +main = App() diff --git a/frameworks/Python/pyvoy/app_wsgi.py b/frameworks/Python/pyvoy/app_wsgi.py new file mode 100644 index 00000000000..c2aa956488d --- /dev/null +++ b/frameworks/Python/pyvoy/app_wsgi.py @@ -0,0 +1,33 @@ +import orjson + + +JSON_HEADERS = [('content-type', 'application/json')] +PLAINTEXT_HEADERS = [('content-type', 'text/plain; charset=utf-8')] + +json_dumps = orjson.dumps + + +def route_json(environ, proto): + proto('200 OK', JSON_HEADERS) + return [json_dumps({'message': 'Hello, world!'})] + + +def route_plaintext(environ, proto): + proto('200 OK', PLAINTEXT_HEADERS) + return [b'Hello, world!'] + + +def handle_404(environ, proto): + proto('404 NOT FOUND', PLAINTEXT_HEADERS) + return [b"not found"] + + +routes = { + '/json': route_json, + '/plaintext': route_plaintext +} + + +def main(environ, proto): + handler = routes.get(environ["PATH_INFO"], handle_404) + return handler(environ, proto) diff --git a/frameworks/Python/pyvoy/benchmark_config.json b/frameworks/Python/pyvoy/benchmark_config.json new file mode 100644 index 00000000000..e5ab6afe780 --- /dev/null +++ b/frameworks/Python/pyvoy/benchmark_config.json @@ -0,0 +1,45 @@ +{ + "framework": "pyvoy", + "tests": [{ + "default": { + "json_url": "/json", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "pyvoy", + "language": "Python", + "orm": "Raw", + "platform": "None", + "webserver": "pyvoy", + "os": "Linux", + "database_os": "Linux", + "display_name": "pyvoy [asgi]", + "notes": "", + "versus": "granian" + }, + "wsgi": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "pyvoy", + "language": "Python", + "orm": "Raw", + "platform": "None", + "webserver": "pyvoy", + "os": "Linux", + "database_os": "Linux", + "display_name": "pyvoy [wsgi]", + "notes": "", + "versus": "granian" + } + }] +} diff --git a/frameworks/Python/pyvoy/config.toml b/frameworks/Python/pyvoy/config.toml new file mode 100644 index 00000000000..585ac12b3c8 --- /dev/null +++ b/frameworks/Python/pyvoy/config.toml @@ -0,0 +1,32 @@ +[framework] +name = "pyvoy" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "pyvoy" +versus = "granian" + +[wsgi] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "pyvoy" +versus = "granian" diff --git a/frameworks/Python/pyvoy/pyvoy-wsgi.dockerfile b/frameworks/Python/pyvoy/pyvoy-wsgi.dockerfile new file mode 100644 index 00000000000..bc0573cf777 --- /dev/null +++ b/frameworks/Python/pyvoy/pyvoy-wsgi.dockerfile @@ -0,0 +1,11 @@ +FROM python:3.13-slim + +ADD ./ /app + +WORKDIR /app + +RUN pip install -r /app/requirements.txt + +EXPOSE 8080 + +CMD ["pyvoy", "--interface", "wsgi", "app_wsgi:main", "--address=0.0.0.0", "--port", "8080"] \ No newline at end of file diff --git a/frameworks/Python/pyvoy/pyvoy.dockerfile b/frameworks/Python/pyvoy/pyvoy.dockerfile new file mode 100644 index 00000000000..8a45efca9a3 --- /dev/null +++ b/frameworks/Python/pyvoy/pyvoy.dockerfile @@ -0,0 +1,11 @@ +FROM python:3.13-slim + +ADD ./ /app + +WORKDIR /app + +RUN pip install -r /app/requirements.txt + +EXPOSE 8080 + +CMD ["pyvoy", "app_asgi:main", "--address=0.0.0.0", "--port", "8080"] diff --git a/frameworks/Python/pyvoy/requirements.txt b/frameworks/Python/pyvoy/requirements.txt new file mode 100644 index 00000000000..b926767af44 --- /dev/null +++ b/frameworks/Python/pyvoy/requirements.txt @@ -0,0 +1,4 @@ +asyncpg==0.30.0 +pyvoy==0.1.2 +jinja2==3.1.6 +orjson==3.11.6 diff --git a/frameworks/Python/pyvoy/templates/fortune.html b/frameworks/Python/pyvoy/templates/fortune.html new file mode 100644 index 00000000000..1c90834285d --- /dev/null +++ b/frameworks/Python/pyvoy/templates/fortune.html @@ -0,0 +1,10 @@ + + +Fortunes + + + +{% for fortune in fortunes %} +{% endfor %}
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
+ + diff --git a/frameworks/Python/sanic/app.py b/frameworks/Python/sanic/app.py index 4070503205d..9dfe864f904 100644 --- a/frameworks/Python/sanic/app.py +++ b/frameworks/Python/sanic/app.py @@ -20,7 +20,6 @@ READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' READ_ROW_SQL_TO_UPDATE = 'SELECT "id", "randomnumber" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, 'Additional fortune added at request time.'] def load_fortunes_template(): @@ -108,7 +107,7 @@ async def fortunes_view(request): async with request.app.ctx.pool.acquire() as connection: fortunes = await connection.fetch('SELECT * FROM Fortune') - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, 'Additional fortune added at request time.']) fortunes.sort(key=sort_fortunes_key) content = template.render(fortunes=fortunes) return response.html(content, headers=get_headers()) diff --git a/frameworks/Python/sanic/requirements.txt b/frameworks/Python/sanic/requirements.txt index ff8b4afd8a9..964877f60b3 100644 --- a/frameworks/Python/sanic/requirements.txt +++ b/frameworks/Python/sanic/requirements.txt @@ -1,5 +1,5 @@ -asyncpg==0.29.0 -Jinja2==3.1.4 -sanic==24.6.0 -uvloop==0.20.0 -orjson==3.10.7 \ No newline at end of file +asyncpg==0.31.0 +Jinja2==3.1.6 +sanic==25.3.0 +uvloop==0.22.1 +orjson==3.11.6 \ No newline at end of file diff --git a/frameworks/Python/sanic/sanic.dockerfile b/frameworks/Python/sanic/sanic.dockerfile index d12ebcb391a..442c2d0eaa5 100644 --- a/frameworks/Python/sanic/sanic.dockerfile +++ b/frameworks/Python/sanic/sanic.dockerfile @@ -1,8 +1,8 @@ -FROM python:3.12 +FROM python:3.14 ADD ./requirements.txt /sanic/requirements.txt -RUN pip3 install cython==3.0.11 && \ +RUN pip3 install cython==3.2.3 && \ pip3 install -r /sanic/requirements.txt ADD ./ /sanic diff --git a/frameworks/Python/socketify.py/requirements-python3.txt b/frameworks/Python/socketify.py/requirements-python3.txt index f9b0ee26ca5..9964258fe37 100644 --- a/frameworks/Python/socketify.py/requirements-python3.txt +++ b/frameworks/Python/socketify.py/requirements-python3.txt @@ -1,2 +1,2 @@ -git+https://github.com/cirospaciari/socketify.py.git@main#socketify +https://github.com/cirospaciari/socketify.py/archive/refs/heads/main.zip#egg=socketify ujson \ No newline at end of file diff --git a/frameworks/Python/socketify.py/requirements.txt b/frameworks/Python/socketify.py/requirements.txt index 7a22543c234..a6d212edf2e 100644 --- a/frameworks/Python/socketify.py/requirements.txt +++ b/frameworks/Python/socketify.py/requirements.txt @@ -1 +1 @@ -git+https://github.com/cirospaciari/socketify.py.git@main#socketify \ No newline at end of file +https://github.com/cirospaciari/socketify.py/archive/refs/heads/main.zip#egg=socketify \ No newline at end of file diff --git a/frameworks/Python/starlette/app.py b/frameworks/Python/starlette/app.py index 86ab80aad58..ae860c057af 100755 --- a/frameworks/Python/starlette/app.py +++ b/frameworks/Python/starlette/app.py @@ -9,7 +9,6 @@ READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, 'Additional fortune added at request time.'] @@ -68,7 +67,7 @@ async def fortunes(request): async with connection_pool.acquire() as connection: fortunes = await connection.fetch('SELECT * FROM Fortune') - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, 'Additional fortune added at request time.']) fortunes.sort(key=lambda row: row[1]) return templates.TemplateResponse("fortune.html", {"fortunes": fortunes, "request": request}) diff --git a/frameworks/Python/tornado/server_uvloop.py b/frameworks/Python/tornado/server_uvloop.py index 8caa8e7355e..7e0e8322764 100644 --- a/frameworks/Python/tornado/server_uvloop.py +++ b/frameworks/Python/tornado/server_uvloop.py @@ -17,7 +17,6 @@ READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, 'Additional fortune added at request time.'] sort_fortunes_key = itemgetter(1) @@ -105,7 +104,7 @@ async def get(self): async with self.application.pool.acquire() as connection: fortunes = await connection.fetch('SELECT * FROM Fortune') - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, 'Additional fortune added at request time.']) fortunes.sort(key=sort_fortunes_key) self.set_header("Content-Type", "text/html; charset=UTF-8") diff --git a/frameworks/Python/uvicorn/app.py b/frameworks/Python/uvicorn/app.py index 40fdb2208f2..77bd7cca8b4 100644 --- a/frameworks/Python/uvicorn/app.py +++ b/frameworks/Python/uvicorn/app.py @@ -21,7 +21,6 @@ async def setup(): READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' -ADDITIONAL_ROW = [0, 'Additional fortune added at request time.'] JSON_RESPONSE = { 'type': 'http.response.start', @@ -142,7 +141,7 @@ async def fortunes(scope, receive, send): finally: await pool.release(connection) - fortunes.append(ADDITIONAL_ROW) + fortunes.append([0, 'Additional fortune added at request time.']) fortunes.sort(key=key) content = template.render(fortunes=fortunes).encode('utf-8') await send(HTML_RESPONSE) diff --git a/frameworks/Ruby/agoo/Gemfile.lock b/frameworks/Ruby/agoo/Gemfile.lock index 8fced2a2ec4..6a95c87f5e0 100644 --- a/frameworks/Ruby/agoo/Gemfile.lock +++ b/frameworks/Ruby/agoo/Gemfile.lock @@ -2,15 +2,15 @@ GEM remote: https://rubygems.org/ specs: agoo (2.15.13) - bigdecimal (3.3.1) + bigdecimal (4.0.1) connection_pool (2.5.0) oj (3.16.12) bigdecimal (>= 3.0) ostruct (>= 0.2) ostruct (0.6.3) - pg (1.6.2) - pg (1.6.2-x86_64-linux) - rack (3.2.0) + pg (1.6.3) + pg (1.6.3-x86_64-linux) + rack (3.2.5) PLATFORMS ruby @@ -24,4 +24,4 @@ DEPENDENCIES rack BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/agoo/agoo.dockerfile b/frameworks/Ruby/agoo/agoo.dockerfile index 3f0e73a6f74..3ee64442984 100644 --- a/frameworks/Ruby/agoo/agoo.dockerfile +++ b/frameworks/Ruby/agoo/agoo.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 RUN apt-get update -q \ && apt-get install --no-install-recommends -q -y \ @@ -21,5 +21,4 @@ RUN bundle install --jobs=4 EXPOSE 8080 - CMD AGOO_WORKER_COUNT=$(nproc) ruby app.rb diff --git a/frameworks/Ruby/agoo/app.rb b/frameworks/Ruby/agoo/app.rb index 2c8e64bc9a9..f14ad897a9d 100644 --- a/frameworks/Ruby/agoo/app.rb +++ b/frameworks/Ruby/agoo/app.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -require 'agoo' -require 'connection_pool' -require 'oj' -require 'pg' -require 'rack' +require 'bundler/setup' +Bundler.require(:default) # Load core modules $pool = ConnectionPool.new(size: 1, timeout: 5) do conn = PG::Connection.new({ @@ -14,7 +11,7 @@ password: 'benchmarkdbpass' }) conn.set_error_verbosity(PG::PQERRORS_VERBOSE) - conn.prepare('select_world', 'SELECT * FROM world WHERE id = $1') + conn.prepare('select_world', 'SELECT id, randomNumber FROM world WHERE id = $1') conn.prepare('select_fortune', 'SELECT id, message FROM fortune') conn end @@ -114,18 +111,15 @@ def self.call(_req) end end - class FortunesHandler < BaseHandler def self.call(_req) - f_1 = $pool.with do |conn| + fortunes = $pool.with do |conn| conn.exec_prepared('select_fortune', []) - end + end.map(&:to_h) + fortunes << { 'id' => 0, 'message' => 'Additional fortune added at request time.' } + fortunes.sort_by! { |fortune| fortune['message'] } - f_2 = f_1.map(&:to_h). - append({ 'id' => '0', 'message' => 'Additional fortune added at request time.' }). - sort_by { |item| item['message'] }. - map { |f| "#{ f['id'] }#{ ERB::Escape.html_escape(f['message']) }" }. - join + rows = fortunes.map { |fortune| "#{fortune['id']}#{ERB::Escape.html_escape(fortune['message'])}" }.join html_response(<<-HTML) @@ -139,7 +133,7 @@ def self.call(_req) id message - #{ f_2 } + #{rows} diff --git a/frameworks/Ruby/grape/Gemfile b/frameworks/Ruby/grape/Gemfile index 7a551b00b76..d938f35b28e 100644 --- a/frameworks/Ruby/grape/Gemfile +++ b/frameworks/Ruby/grape/Gemfile @@ -1,9 +1,9 @@ source 'https://rubygems.org' -gem 'mysql2', '0.5.6' gem 'activerecord', '~> 8.1.0', :require => 'active_record' -gem 'grape', '2.1.1' -gem 'json', '~> 2.9' +gem 'grape', '~> 3.0' +gem 'pg' +gem 'json' group :iodine, optional: true do gem "iodine", "~> 0.7", require: false diff --git a/frameworks/Ruby/grape/Gemfile.lock b/frameworks/Ruby/grape/Gemfile.lock index d79d4469104..a836ecf9896 100644 --- a/frameworks/Ruby/grape/Gemfile.lock +++ b/frameworks/Ruby/grape/Gemfile.lock @@ -20,11 +20,14 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) - base64 (0.2.0) - bigdecimal (3.1.9) + base64 (0.3.0) + bigdecimal (3.3.1) concurrent-ruby (1.3.5) - connection_pool (2.5.0) - drb (2.2.1) + connection_pool (3.0.2) + drb (2.2.3) + dry-configurable (1.3.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) dry-core (1.1.0) concurrent-ruby (~> 1.0) logger @@ -35,15 +38,16 @@ GEM concurrent-ruby (~> 1.0) dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-types (1.8.2) + dry-types (1.8.3) bigdecimal (~> 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0) dry-logic (~> 1.4) zeitwerk (~> 2.6) - grape (2.1.1) - activesupport (>= 6) + grape (3.0.1) + activesupport (>= 7.0) + dry-configurable dry-types (>= 1.1) mustermann-grape (~> 1.1.0) rack (>= 2) @@ -51,25 +55,27 @@ GEM i18n (1.14.7) concurrent-ruby (~> 1.0) iodine (0.7.58) - json (2.16.0) - logger (1.6.6) - minitest (5.25.4) - mustermann (3.0.3) + json (2.18.0) + logger (1.7.0) + minitest (5.26.2) + mustermann (3.0.4) ruby2_keywords (~> 0.0.1) mustermann-grape (1.1.0) mustermann (>= 1.0.0) - mysql2 (0.5.6) - nio4r (2.7.4) - puma (7.1.0) + nio4r (2.7.5) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) + puma (7.2.0) nio4r (~> 2.0) - rack (3.2.3) + rack (3.2.4) ruby2_keywords (0.0.5) securerandom (0.4.1) - timeout (0.4.3) + timeout (0.4.4) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - uri (1.0.3) - zeitwerk (2.7.2) + uri (1.1.1) + zeitwerk (2.7.3) PLATFORMS ruby @@ -78,11 +84,11 @@ PLATFORMS DEPENDENCIES activerecord (~> 8.1.0) - grape (= 2.1.1) + grape (~> 3.0) iodine (~> 0.7) - json (~> 2.9) - mysql2 (= 0.5.6) + json + pg puma (~> 7.1) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/grape/benchmark_config.json b/frameworks/Ruby/grape/benchmark_config.json index dd8892f5ea9..dff410eb2cf 100644 --- a/frameworks/Ruby/grape/benchmark_config.json +++ b/frameworks/Ruby/grape/benchmark_config.json @@ -10,7 +10,7 @@ "port": 8080, "approach": "Realistic", "classification": "Micro", - "database": "MySQL", + "database": "Postgres", "framework": "grape", "language": "Ruby", "orm": "Full", @@ -20,7 +20,7 @@ "database_os": "Linux", "display_name": "grape [puma]", "notes": "", - "versus": "rack-puma-mri" + "versus": "rack" }, "iodine": { "json_url": "/json", @@ -31,7 +31,7 @@ "port": 8080, "approach": "Realistic", "classification": "Micro", - "database": "MySQL", + "database": "Postgres", "framework": "grape", "language": "Ruby", "orm": "Full", @@ -41,7 +41,7 @@ "database_os": "Linux", "display_name": "grape [iodine]", "notes": "", - "versus": "rack-iodine-mri" + "versus": "rack-iodine" } }] } diff --git a/frameworks/Ruby/grape/boot.rb b/frameworks/Ruby/grape/boot.rb deleted file mode 100644 index dd2ffda7f0e..00000000000 --- a/frameworks/Ruby/grape/boot.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'erb' -require 'active_record' -require 'yaml' - -MAX_PK = 10_000 -ID_RANGE = (1..MAX_PK).freeze -ALL_IDS = ID_RANGE.to_a -QUERIES_MIN = 1 -QUERIES_MAX = 500 - -Bundler.require :default - -db_config = YAML.load(ERB.new(File.read('config/database.yml')).result)[ENV['RACK_ENV']] -ActiveRecord::Base.establish_connection(db_config) - -class World < ActiveRecord::Base - self.table_name = 'World' -end - -module Acme - class HelloWorld < Grape::API - get '/json' do - {message:'Hello, World!'} - end - end - - class PlainText < Grape::API - content_type :plain, 'text/plain' - format :plain - - get '/plaintext' do - 'Hello, World!' - end - end - - class DatabaseQueries < Grape::API - logger nil - helpers do - def bounded_queries - queries = params[:queries].to_i - queries.clamp(QUERIES_MIN, QUERIES_MAX) - end - - # Return a random number between 1 and MAX_PK - def rand1 - rand(MAX_PK).succ - end - end - - get '/db' do - ActiveRecord::Base.with_connection do - World.find(rand1).attributes - end - end - - get '/query' do - ActiveRecord::Base.with_connection do - ALL_IDS.sample(bounded_queries).map do |id| - World.find(id) - end - end - end - - get '/updates' do - worlds = - ActiveRecord::Base.with_connection do - ALL_IDS.sample(bounded_queries).map do |id| - world = World.find(id) - new_value = rand1 - new_value = rand1 while new_value == world.randomNumber - world.update_columns(randomNumber: new_value) - world - end - end - end - end - - class API < Grape::API - before do - header 'Date', Time.now.httpdate if defined?(Puma) - header 'Server', 'grape' - end - logger nil - content_type :json, 'application/json' - format :json - - mount ::Acme::HelloWorld - mount ::Acme::PlainText - mount ::Acme::DatabaseQueries - end -end diff --git a/frameworks/Ruby/grape/config.ru b/frameworks/Ruby/grape/config.ru index 54d0ce8ca74..72a7931a5ad 100644 --- a/frameworks/Ruby/grape/config.ru +++ b/frameworks/Ruby/grape/config.ru @@ -1,2 +1,5 @@ -require_relative 'boot' +# frozen_string_literal: true + +require_relative 'hello_world' + run Acme::API diff --git a/frameworks/Ruby/grape/config/auto_tune.rb b/frameworks/Ruby/grape/config/auto_tune.rb deleted file mode 100644 index aff6b73b997..00000000000 --- a/frameworks/Ruby/grape/config/auto_tune.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - raise "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - [(Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil, MIN_WORKERS].max - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $PROGRAM_NAME == __FILE__ diff --git a/frameworks/Ruby/grape/config/database.yml b/frameworks/Ruby/grape/config/database.yml index 32ce75b69bf..2d7fa13cc54 100644 --- a/frameworks/Ruby/grape/config/database.yml +++ b/frameworks/Ruby/grape/config/database.yml @@ -1,5 +1,5 @@ production: - adapter: mysql2 + adapter: postgresql encoding: utf8 host: tfb-database database: hello_world @@ -7,3 +7,4 @@ production: password: benchmarkdbpass pool: <%= ENV.fetch('MAX_THREADS') %> timeout: 5000 + encoding: unicode diff --git a/frameworks/Ruby/grape/db.rb b/frameworks/Ruby/grape/db.rb new file mode 100644 index 00000000000..a7a5de31414 --- /dev/null +++ b/frameworks/Ruby/grape/db.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'erb' +require 'active_record' +require 'yaml' + +db_config = YAML.load(ERB.new(File.read('config/database.yml')).result)[ENV['RACK_ENV']] +ActiveRecord::Base.establish_connection(db_config) +ActiveRecord::Base.logger = nil + +class World < ActiveRecord::Base + self.table_name = 'World' + + alias_attribute(:randomNumber, :randomnumber) \ + if connection.adapter_name.downcase.start_with?('postgres') +end + diff --git a/frameworks/Ruby/grape/grape-iodine.dockerfile b/frameworks/Ruby/grape/grape-iodine.dockerfile index 4e20c95ba1c..a2d7c2bb4f3 100644 --- a/frameworks/Ruby/grape/grape-iodine.dockerfile +++ b/frameworks/Ruby/grape/grape-iodine.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 @@ -7,8 +7,6 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends libjemalloc2 ENV LD_PRELOAD=libjemalloc.so.2 -RUN apt-get update -yqq && apt-get install -yqq nginx - ADD ./ /grape WORKDIR /grape @@ -21,4 +19,4 @@ ENV MAX_THREADS=1 EXPOSE 8080 -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/grape/grape.dockerfile b/frameworks/Ruby/grape/grape.dockerfile index 2ef47fcaed2..1c40ea8e876 100644 --- a/frameworks/Ruby/grape/grape.dockerfile +++ b/frameworks/Ruby/grape/grape.dockerfile @@ -1,6 +1,7 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -15,6 +16,7 @@ RUN bundle config set with 'puma' RUN bundle install --jobs=8 --gemfile=/grape/Gemfile ENV WEB_CONCURRENCY=auto +ENV MIN_THREADS=5 ENV MAX_THREADS=5 EXPOSE 8080 diff --git a/frameworks/Ruby/grape/hello_world.rb b/frameworks/Ruby/grape/hello_world.rb new file mode 100644 index 00000000000..0605b48243f --- /dev/null +++ b/frameworks/Ruby/grape/hello_world.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'bundler/setup' +Bundler.require :default + +require_relative 'db' + +module Acme + MAX_PK = 10_000 + ID_RANGE = (1..MAX_PK).freeze + ALL_IDS = ID_RANGE.to_a + QUERIES_MIN = 1 + QUERIES_MAX = 500 + + class HelloWorld < Grape::API + get '/json' do + {message:'Hello, World!'} + end + end + + class PlainText < Grape::API + content_type :plain, 'text/plain' + format :plain + + get '/plaintext' do + 'Hello, World!' + end + end + + class DatabaseQueries < Grape::API + logger nil + helpers do + def bounded_queries + queries = params[:queries].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end + + # Return a random number between 1 and MAX_PK + def rand1 + rand(MAX_PK).succ + end + end + + get '/db' do + ActiveRecord::Base.with_connection do + World.find(rand1).attributes + end + end + + get '/query' do + ActiveRecord::Base.with_connection do + ALL_IDS.sample(bounded_queries).map do |id| + World.find(id).attributes + end + end + end + + get '/updates' do + worlds = nil + ids = ALL_IDS.sample(bounded_queries) + ActiveRecord::Base.with_connection do + worlds = ids.map do |id| + world = World.find(id) + new_value = rand1 + new_value = rand1 until new_value != world.randomNumber + { id: id, randomnumber: new_value } + end + end + worlds.sort_by!{_1[:id]} + ActiveRecord::Base.with_connection do + World.upsert_all(worlds) + end + worlds + end + end + + class API < Grape::API + before do + header 'Date', Time.now.httpdate if defined?(Puma) + header 'Server', 'grape' + end + logger nil + content_type :json, 'application/json' + format :json + + mount ::Acme::HelloWorld + mount ::Acme::PlainText + mount ::Acme::DatabaseQueries + end +end diff --git a/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile b/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile index aaf6a6eaa96..6676abd6fa2 100644 --- a/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile +++ b/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile @@ -1,10 +1,10 @@ -ARG UBUNTU_VERSION=25.10 +ARG UBUNTU_VERSION=26.04 ARG H2O_PREFIX=/opt/h2o FROM "buildpack-deps:${UBUNTU_VERSION}" AS compile -ARG H2O_VERSION=3b9b6a53cac8bcc6a25fb28df81ad295fc5f9402 +ARG H2O_VERSION=ccea64b17ade832753db933658047ede9f31a380 ARG DEBIAN_FRONTEND=noninteractive ARG H2O_PREFIX @@ -20,24 +20,22 @@ RUN apt-get install \ libssl-dev \ liburing-dev \ libuv1-dev \ - libwslay-dev \ libz-dev \ make \ - ninja-build \ pkg-config \ ruby \ - systemtap-sdt-dev && \ + systemtap-sdt-dev > /dev/null && \ curl -LSs "https://github.com/h2o/h2o/archive/${H2O_VERSION}.tar.gz" | \ - tar --strip-components=1 -xz && \ + tar --strip-components=1 -xz > /dev/null && \ cmake \ -B build \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ -DCMAKE_INSTALL_PREFIX="${H2O_PREFIX}" \ -DWITH_MRUBY=on \ - -G Ninja \ - -S . && \ - cmake --build build -j && \ - cmake --install build + -S . > /dev/null && \ + cmake --build build -j > /dev/null && \ + cmake --install build > /dev/null FROM "ubuntu:${UBUNTU_VERSION}" diff --git a/frameworks/Ruby/hanami/.gitignore b/frameworks/Ruby/hanami/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/hanami/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/hanami/Gemfile b/frameworks/Ruby/hanami/Gemfile index 2065c222246..c2260011c0f 100644 --- a/frameworks/Ruby/hanami/Gemfile +++ b/frameworks/Ruby/hanami/Gemfile @@ -10,10 +10,12 @@ gem "hanami-validations", "~> 2.3" gem "hanami-view", "~> 2.3" gem "dry-types", "~> 1.0", ">= 1.6.1" -gem "puma" gem "rake" gem "rom", "~> 5.3" gem "rom-sql", "~> 3.6" gem "pg" -gem "ostruct" # required for Ruby 4.0 + +group :iodine, optional: true do + gem 'iodine', '~> 0.7' +end diff --git a/frameworks/Ruby/hanami/Gemfile.lock b/frameworks/Ruby/hanami/Gemfile.lock index 953659b0535..a9b884b4efe 100644 --- a/frameworks/Ruby/hanami/Gemfile.lock +++ b/frameworks/Ruby/hanami/Gemfile.lock @@ -2,8 +2,8 @@ GEM remote: https://rubygems.org/ specs: base64 (0.3.0) - bigdecimal (3.1.9) - concurrent-ruby (1.3.5) + bigdecimal (3.3.1) + concurrent-ruby (1.3.6) csv (3.3.5) date (3.5.0) dry-auto_inject (1.1.0) @@ -53,7 +53,7 @@ GEM dry-inflector (~> 1.1) dry-transformer (1.0.1) zeitwerk (~> 2.6) - dry-types (1.8.2) + dry-types (1.8.3) bigdecimal (~> 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) @@ -121,28 +121,27 @@ GEM hansi (0.2.1) ice_nine (0.11.2) io-console (0.8.1) + iodine (0.7.58) irb (1.15.3) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.16.0) - logger (1.6.6) + json (2.18.0) + logger (1.7.0) mustermann (3.0.3) ruby2_keywords (~> 0.0.1) mustermann-contrib (3.0.3) hansi (~> 0.2.0) mustermann (= 3.0.3) - nio4r (2.7.4) - ostruct (0.6.3) - pg (1.5.9) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) pp (0.6.3) prettyprint prettyprint (0.2.0) psych (5.2.6) date stringio - puma (6.6.0) - nio4r (~> 2.0) rack (3.2.4) rack-session (2.1.1) base64 (>= 0.1.0) @@ -156,10 +155,10 @@ GEM tsort reline (0.6.3) io-console (~> 0.5) - rom (5.4.2) + rom (5.4.3) rom-changeset (~> 5.4) rom-core (~> 5.4) - rom-repository (~> 5.4, >= 5.4.2) + rom-repository (~> 5.4, >= 5.4.3) rom-changeset (5.4.0) dry-core (~> 1.0) rom-core (~> 5.4) @@ -173,7 +172,7 @@ GEM dry-struct (~> 1.0) dry-types (~> 1.6) transproc (~> 1.1) - rom-repository (5.4.2) + rom-repository (5.4.3) dry-core (~> 1.0) dry-initializer (~> 3.2) rom-core (~> 5.4) @@ -190,7 +189,7 @@ GEM tilt (2.6.0) transproc (1.1.1) tsort (0.2.0) - zeitwerk (2.7.2) + zeitwerk (2.7.4) PLATFORMS ruby @@ -205,12 +204,11 @@ DEPENDENCIES hanami-router (~> 2.3) hanami-validations (~> 2.3) hanami-view (~> 2.3) - ostruct + iodine (~> 0.7) pg - puma rake rom (~> 5.3) rom-sql (~> 3.6) BUNDLED WITH - 2.7.0 + 2.7.0 diff --git a/frameworks/Ruby/hanami/app/action.rb b/frameworks/Ruby/hanami/app/action.rb index 8ef93e34f4a..749cb8b8328 100644 --- a/frameworks/Ruby/hanami/app/action.rb +++ b/frameworks/Ruby/hanami/app/action.rb @@ -11,7 +11,7 @@ class Action < Hanami::Action def set_headers(*, response) response.headers['Server'] = 'hanami' - response.headers['Date'] = Time.now.httpdate + response.headers['Date'] = Time.now.httpdate if defined?(Puma) end end end diff --git a/frameworks/Ruby/hanami/app/actions/db/index.rb b/frameworks/Ruby/hanami/app/actions/db/index.rb index e5efcc2f414..3b67c404287 100644 --- a/frameworks/Ruby/hanami/app/actions/db/index.rb +++ b/frameworks/Ruby/hanami/app/actions/db/index.rb @@ -11,7 +11,7 @@ class Index < HelloWorld::Action def handle(*, response) world = world_repo.find(random_id) response.format = :json - response.body = world.to_h.to_json + response.body = JSON.generate(world.to_h) end def random_id diff --git a/frameworks/Ruby/hanami/app/actions/queries/index.rb b/frameworks/Ruby/hanami/app/actions/queries/index.rb index d20dfc2df3a..2dda18b8438 100644 --- a/frameworks/Ruby/hanami/app/actions/queries/index.rb +++ b/frameworks/Ruby/hanami/app/actions/queries/index.rb @@ -16,7 +16,7 @@ def handle(request, response) world_repo.find(id) end response.format = :json - response.body = worlds.map(&:to_h).to_json + response.body = JSON.generate(worlds.map(&:to_h)) end private diff --git a/frameworks/Ruby/hanami/app/actions/updates/index.rb b/frameworks/Ruby/hanami/app/actions/updates/index.rb index 3e68be733be..d31d18f3ab2 100644 --- a/frameworks/Ruby/hanami/app/actions/updates/index.rb +++ b/frameworks/Ruby/hanami/app/actions/updates/index.rb @@ -16,7 +16,7 @@ def handle(request, response) world_repo.update_random_number(id) end response.format = :json - response.body = worlds.to_json + response.body = JSON.generate(worlds) end private diff --git a/frameworks/Ruby/hanami/benchmark_config.json b/frameworks/Ruby/hanami/benchmark_config.json index 1a081210b16..9ca0fc2eedb 100644 --- a/frameworks/Ruby/hanami/benchmark_config.json +++ b/frameworks/Ruby/hanami/benchmark_config.json @@ -16,12 +16,12 @@ "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Puma", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", "display_name": "hanami", "notes": "", - "versus": "" + "versus": "rack-iodine" } }] } diff --git a/frameworks/Ruby/hanami/config/routes.rb b/frameworks/Ruby/hanami/config/routes.rb index b57e5af753f..e438a379241 100644 --- a/frameworks/Ruby/hanami/config/routes.rb +++ b/frameworks/Ruby/hanami/config/routes.rb @@ -9,7 +9,7 @@ class Routes < Hanami::Routes 'Content-Type' => 'application/json', 'Date' => Time.now.httpdate, }, - [{ 'message' => 'Hello, World!' }.to_json]] + [JSON.generate({ 'message' => 'Hello, World!' })]] end get "/db", to: "db.index" get "/queries", to: "queries.index" diff --git a/frameworks/Ruby/hanami/hanami.dockerfile b/frameworks/Ruby/hanami/hanami.dockerfile index 172d55b4946..10dafe5fc6d 100644 --- a/frameworks/Ruby/hanami/hanami.dockerfile +++ b/frameworks/Ruby/hanami/hanami.dockerfile @@ -1,7 +1,6 @@ -FROM ruby:3.5-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 -ENV WEB_CONCURRENCY=auto # Use Jemalloc RUN apt-get update && \ @@ -12,6 +11,7 @@ ADD ./ /hanami WORKDIR /hanami ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'iodine' RUN bundle install --jobs=8 EXPOSE 8080 @@ -20,4 +20,4 @@ ENV HANAMI_ENV=production ENV HANAMI_PORT=8080 ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world -CMD bundle exec hanami server +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/padrino/.gitignore b/frameworks/Ruby/padrino/.gitignore new file mode 100644 index 00000000000..5cca892bf7e --- /dev/null +++ b/frameworks/Ruby/padrino/.gitignore @@ -0,0 +1,3 @@ +.history +.devcontainer +tmp diff --git a/frameworks/Ruby/padrino/Gemfile b/frameworks/Ruby/padrino/Gemfile index 4e9aa2922ea..b24e592353e 100644 --- a/frameworks/Ruby/padrino/Gemfile +++ b/frameworks/Ruby/padrino/Gemfile @@ -1,13 +1,12 @@ source 'https://rubygems.org' -gem 'mysql2', '> 0.5' +gem 'activerecord', '~> 8.1.0', require: 'active_record' gem 'json' -gem 'activerecord', '~> 8.1.0', :require => 'active_record' - -gem 'slim' -gem 'padrino', '0.16.0' -gem 'rack' gem 'ostruct' # required for Ruby 3.5 +gem 'padrino', '~> 0.16' +gem 'pg' +gem 'rack' +gem 'slim' group :iodine, optional: true do gem "iodine", "~> 0.7", require: false diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock index b62ac92b5c5..4e4b06c3538 100644 --- a/frameworks/Ruby/padrino/Gemfile.lock +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -23,7 +23,7 @@ GEM base64 (0.3.0) bigdecimal (3.1.9) concurrent-ruby (1.3.5) - connection_pool (2.5.0) + connection_pool (3.0.2) date (3.5.0) drb (2.2.1) i18n (1.14.7) @@ -46,7 +46,6 @@ GEM moneta (1.6.0) mustermann (3.0.4) ruby2_keywords (~> 0.0.1) - mysql2 (0.5.6) net-imap (0.5.12) date net-protocol @@ -89,6 +88,9 @@ GEM mime-types (>= 3.1, < 4) padrino-core (= 0.16.0) padrino-support (0.16.0) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) rack (3.2.4) rack-protection (4.2.1) base64 (>= 0.1.0) @@ -128,9 +130,9 @@ DEPENDENCIES activerecord (~> 8.1.0) iodine (~> 0.7) json - mysql2 (> 0.5) ostruct - padrino (= 0.16.0) + padrino (~> 0.16) + pg rack slim diff --git a/frameworks/Ruby/padrino/app/controllers.rb b/frameworks/Ruby/padrino/app/controllers.rb index e5a200c7f2c..f9a68b87539 100644 --- a/frameworks/Ruby/padrino/app/controllers.rb +++ b/frameworks/Ruby/padrino/app/controllers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + QUERY_RANGE = (1..10_000).freeze ALL_IDS = QUERY_RANGE.to_a @@ -8,14 +10,14 @@ end get '/json', :provides => [:json] do - {message: "Hello, World!"}.to_json + JSON.generate({message: "Hello, World!"}) end get '/db', :provides => [:json] do world = ActiveRecord::Base.with_connection do World.find(rand1).attributes end - world.to_json + JSON.generate(world) end get '/queries', :provides => [:json] do @@ -24,7 +26,7 @@ World.find(id).attributes end end - worlds.to_json + JSON.generate(worlds) end get '/fortunes' do @@ -45,13 +47,13 @@ world = World.find(id) new_value = rand1 new_value = rand1 while new_value == world.randomNumber - world.randomNumber = new_value - world + { id: id, randomNumber: new_value } end + worlds.sort_by!{_1[:id]} World.upsert_all(worlds) end - worlds.to_json + JSON.generate(worlds) end get '/plaintext' do diff --git a/frameworks/Ruby/padrino/benchmark_config.json b/frameworks/Ruby/padrino/benchmark_config.json index 0eaf86be1d9..f46cec04e07 100644 --- a/frameworks/Ruby/padrino/benchmark_config.json +++ b/frameworks/Ruby/padrino/benchmark_config.json @@ -11,7 +11,7 @@ "port": 8080, "approach": "Realistic", "classification": "Micro", - "database": "MySQL", + "database": "Postgres", "framework": "padrino", "language": "Ruby", "orm": "Full", @@ -21,7 +21,7 @@ "database_os": "Linux", "display_name": "padrino", "notes": "", - "versus": "rack-iodine" + "versus": "sinatra" } }] } diff --git a/frameworks/Ruby/padrino/config/auto_tune.rb b/frameworks/Ruby/padrino/config/auto_tune.rb deleted file mode 100644 index 54ae1e08731..00000000000 --- a/frameworks/Ruby/padrino/config/auto_tune.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 128 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - fail "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - (Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $0 == __FILE__ diff --git a/frameworks/Ruby/padrino/config/database.rb b/frameworks/Ruby/padrino/config/database.rb index c4bf9d564d2..f247ddf5292 100644 --- a/frameworks/Ruby/padrino/config/database.rb +++ b/frameworks/Ruby/padrino/config/database.rb @@ -1,10 +1,10 @@ -Bundler.require('mysql') +Bundler.require('pg') opts = { - adapter: 'mysql2', + adapter: 'postgresql', username: 'benchmarkdbuser', password: 'benchmarkdbpass', host: 'tfb-database', - database: 'hello_world' + database: 'hello_world', } # Determine threading/thread pool size and timeout @@ -12,9 +12,8 @@ opts[:pool] = 512 opts[:checkout_timeout] = 5 - # Setup our logger -ActiveRecord::Base.logger = logger +ActiveRecord::Base.logger = nil # Use ISO 8601 format for JSON serialized times and dates. ActiveSupport.use_standard_json_time_format = true diff --git a/frameworks/Ruby/padrino/models/world.rb b/frameworks/Ruby/padrino/models/world.rb index 9e7b8d16fb7..2b06bd4d72c 100644 --- a/frameworks/Ruby/padrino/models/world.rb +++ b/frameworks/Ruby/padrino/models/world.rb @@ -3,14 +3,4 @@ class World < ActiveRecord::Base alias_attribute(:randomNumber, :randomnumber) \ if connection.adapter_name.downcase.start_with?('postgres') - - if connection.adapter_name.downcase.start_with?('mysql') - def self.upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) - # On MySQL Batch updates verification isn't supported yet by TechEmpower. - # https://github.com/TechEmpower/FrameworkBenchmarks/issues/5983 - attributes.each do |attrs| - where(id: attrs[:id]).update_all(randomNumber: attrs[:randomNumber]) - end - end - end end diff --git a/frameworks/Ruby/padrino/padrino.dockerfile b/frameworks/Ruby/padrino/padrino.dockerfile index 50cdbe55042..0a1f6ea3f1c 100644 --- a/frameworks/Ruby/padrino/padrino.dockerfile +++ b/frameworks/Ruby/padrino/padrino.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 WORKDIR /padrino COPY app app @@ -18,4 +18,4 @@ EXPOSE 8080 ENV RUBY_YJIT_ENABLE=1 ENV RACK_ENV=production -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/rack-app/.gitignore b/frameworks/Ruby/rack-app/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/rack-app/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/rack-app/Gemfile b/frameworks/Ruby/rack-app/Gemfile index 2ad03adfb21..85cb31591fc 100644 --- a/frameworks/Ruby/rack-app/Gemfile +++ b/frameworks/Ruby/rack-app/Gemfile @@ -4,10 +4,11 @@ source 'https://rubygems.org' gem 'rack-app' gem 'rack-app-front_end' -gem 'iodine', '~> 0.7', platforms: %i[ruby windows] +gem 'cgi' # for Ruby 4.0 +gem 'iodine', '~> 0.7' gem 'irb' # for Ruby 3.5 gem 'logger' # for Ruby 3.5 -gem 'json', '~> 2.10' +gem 'json' gem 'pg', '~> 1.5' gem 'sequel', '~> 5.0' -gem 'sequel_pg', '~> 1.6', require: false +gem 'sequel_pg', '~> 1.17', require: 'sequel' diff --git a/frameworks/Ruby/rack-app/Gemfile.lock b/frameworks/Ruby/rack-app/Gemfile.lock index 2620ee87445..bb503f80935 100644 --- a/frameworks/Ruby/rack-app/Gemfile.lock +++ b/frameworks/Ruby/rack-app/Gemfile.lock @@ -1,7 +1,8 @@ GEM remote: https://rubygems.org/ specs: - bigdecimal (3.3.1) + bigdecimal (4.0.1) + cgi (0.5.1) date (3.5.0) erb (5.1.3) io-console (0.8.1) @@ -10,17 +11,17 @@ GEM pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.16.0) + json (2.18.0) logger (1.7.0) - pg (1.6.2) - pg (1.6.2-arm64-darwin) + pg (1.6.3) + pg (1.6.3-arm64-darwin) pp (0.6.3) prettyprint prettyprint (0.2.0) psych (5.2.6) date stringio - rack (3.2.4) + rack (3.2.5) rack-app (11.0.2) rack (>= 3.0.0) rackup @@ -35,9 +36,9 @@ GEM tsort reline (0.6.2) io-console (~> 0.5) - sequel (5.98.0) + sequel (5.100.0) bigdecimal - sequel_pg (1.17.2) + sequel_pg (1.18.2) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) stringio (3.1.7) @@ -49,15 +50,16 @@ PLATFORMS ruby DEPENDENCIES + cgi iodine (~> 0.7) irb - json (~> 2.10) + json logger pg (~> 1.5) rack-app rack-app-front_end sequel (~> 5.0) - sequel_pg (~> 1.6) + sequel_pg (~> 1.17) BUNDLED WITH - 2.7.2 + 4.0.3 diff --git a/frameworks/Ruby/rack-app/app.rb b/frameworks/Ruby/rack-app/app.rb index e5310fc012d..d08b21e02c8 100644 --- a/frameworks/Ruby/rack-app/app.rb +++ b/frameworks/Ruby/rack-app/app.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true +require 'bundler/setup' +Bundler.require(:default) # Load core modules require 'rack/app' require 'rack/app/front_end' +require_relative 'db' require 'json' +require 'time' class App < Rack::App MAX_PK = 10_000 @@ -19,32 +23,35 @@ class App < Rack::App helpers do def fortunes fortunes = Fortune.all - fortunes << Fortune.new( - id: 0, - message: "Additional fortune added at request time." - ) + + fortune = Fortune.new + fortune.id = 0 + fortune.message = "Additional fortune added at request time." + fortunes << fortune + fortunes.sort_by!(&:message) end end get '/json' do set_headers(JSON_TYPE) - { message: 'Hello, World!' }.to_json + JSON.generate({ message: 'Hello, World!' }) end get '/db' do set_headers(JSON_TYPE) - World.with_pk(rand1).values.to_json + JSON.generate(World.with_pk(rand1).values) end get '/queries' do set_headers(JSON_TYPE) ids = ALL_IDS.sample(bounded_queries) - DB.synchronize do + worlds = DB.synchronize do ids.map do |id| World.with_pk(id).values end - end.to_json + end + JSON.generate(worlds) end get '/fortunes' do @@ -74,3 +81,24 @@ def set_headers(content_type) response.headers['Server'] = 'rack-app' end end + +# Override `expand_path` to use `__FILE__` instead of the expensive `caller`. +module Rack::App::Utils + def expand_path(file_path) + case file_path + + when /^\.\// + #File.expand_path(File.join(File.dirname(caller[1]), file_path)) + File.expand_path(File.join(File.dirname(__FILE__), file_path)) + + when /^[^\/]/ + #File.join(namespace_folder(caller[1]), file_path) + File.join(namespace_folder(__FILE__), file_path) + + when /^\// + from_project_root_path = pwd(file_path) + File.exist?(from_project_root_path) ? from_project_root_path : file_path + + end + end +end diff --git a/frameworks/Ruby/rack-app/benchmark_config.json b/frameworks/Ruby/rack-app/benchmark_config.json index d25acd9a641..7082956d991 100644 --- a/frameworks/Ruby/rack-app/benchmark_config.json +++ b/frameworks/Ruby/rack-app/benchmark_config.json @@ -20,7 +20,8 @@ "os": "Linux", "database_os": "Linux", "display_name": "rack-app", - "notes": "" + "notes": "", + "versus": "rack-iodine" } } ] diff --git a/frameworks/Ruby/rack-app/boot.rb b/frameworks/Ruby/rack-app/boot.rb deleted file mode 100644 index 7711f76a0a1..00000000000 --- a/frameworks/Ruby/rack-app/boot.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true -require 'bundler/setup' -require 'time' - -MAX_PK = 10_000 -ID_RANGE = (1..MAX_PK).freeze -ALL_IDS = ID_RANGE.to_a -QUERIES_MIN = 1 -QUERIES_MAX = 500 -SEQUEL_NO_ASSOCIATIONS = true -#SERVER_STRING = "Sinatra" - -Bundler.require(:default) # Load core modules - -def connect(dbtype) - Bundler.require(dbtype) # Load database-specific modules - - opts = {} - - adapter = 'postgresql' - - # Determine threading/thread pool size and timeout - if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = threads - opts[:pool_timeout] = 10 - else - opts[:max_connections] = 512 - end - - Sequel.connect \ - '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { - adapter: adapter, - host: 'tfb-database', - database: 'hello_world', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass' - }, opts -end - -DB = connect 'postgres' - -# Define ORM models -class World < Sequel::Model(:World) - def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql - - def self.batch_update(worlds) - if DB.database_type == :mysql - worlds.map(&:save_changes) - else - ids = [] - sql = String.new("UPDATE world SET randomnumber = CASE id ") - worlds.each do |world| - sql << "when #{world.id} then #{world.randomnumber} " - ids << world.id - end - sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" - DB.run(sql) - end - end -end - -class Fortune < Sequel::Model(:Fortune) - # Allow setting id to zero (0) per benchmark requirements - unrestrict_primary_key -end - -[World, Fortune].each(&:freeze) -DB.freeze diff --git a/frameworks/Ruby/rack-app/config.ru b/frameworks/Ruby/rack-app/config.ru index 27540c2f4ee..b61a5d5003e 100644 --- a/frameworks/Ruby/rack-app/config.ru +++ b/frameworks/Ruby/rack-app/config.ru @@ -1,5 +1,4 @@ # frozen_string_literal: true -require_relative 'boot' require_relative 'app' run App diff --git a/frameworks/Ruby/rack-app/config/auto_tune.rb b/frameworks/Ruby/rack-app/config/auto_tune.rb deleted file mode 100644 index 1e075f56911..00000000000 --- a/frameworks/Ruby/rack-app/config/auto_tune.rb +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - raise "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - [(Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil, MIN_WORKERS].max - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $PROGRAM_NAME == __FILE__ diff --git a/frameworks/Ruby/rack-app/config/puma.rb b/frameworks/Ruby/rack-app/config/puma.rb deleted file mode 100644 index 1b6d05d8ac0..00000000000 --- a/frameworks/Ruby/rack-app/config/puma.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -_num_workers, num_threads = auto_tune - -threads num_threads - -before_fork do - Sequel::DATABASES.each(&:disconnect) -end diff --git a/frameworks/Ruby/rack-app/db.rb b/frameworks/Ruby/rack-app/db.rb new file mode 100644 index 00000000000..4d51f8b8109 --- /dev/null +++ b/frameworks/Ruby/rack-app/db.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +SEQUEL_NO_ASSOCIATIONS = true + +def connect(dbtype) + Bundler.require(dbtype) # Load database-specific modules + + opts = {} + + adapter = 'postgresql' + + # Determine threading/thread pool size and timeout + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 + opts[:max_connections] = threads + opts[:pool_timeout] = 10 + else + opts[:max_connections] = 512 + end + + Sequel.connect \ + '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { + adapter: adapter, + host: 'tfb-database', + database: 'hello_world', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' + }, opts +end + +DB = connect 'postgres' + +# Define ORM models +class World < Sequel::Model(:World) + def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql + + def self.batch_update(worlds) + if DB.database_type == :mysql + worlds.map(&:save_changes) + else + ids = [] + sql = String.new("UPDATE world SET randomnumber = CASE id ") + worlds.each do |world| + sql << "when #{world.id} then #{world.randomnumber} " + ids << world.id + end + sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" + DB.run(sql) + end + end +end + +class Fortune < Sequel::Model(:Fortune) + # Allow setting id to zero (0) per benchmark requirements + unrestrict_primary_key +end + +[World, Fortune].each(&:freeze) +DB.freeze diff --git a/frameworks/Ruby/rack-app/rack-app.dockerfile b/frameworks/Ruby/rack-app/rack-app.dockerfile index 2b24fcab8bd..17b956e3f82 100644 --- a/frameworks/Ruby/rack-app/rack-app.dockerfile +++ b/frameworks/Ruby/rack-app/rack-app.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 @@ -18,4 +18,4 @@ COPY . . EXPOSE 8080 -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/rack-sequel/.gitignore b/frameworks/Ruby/rack-sequel/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/rack-sequel/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/rack-sequel/Gemfile b/frameworks/Ruby/rack-sequel/Gemfile index fa1f161147d..b60fdd3d8ed 100644 --- a/frameworks/Ruby/rack-sequel/Gemfile +++ b/frameworks/Ruby/rack-sequel/Gemfile @@ -1,19 +1,24 @@ source 'https://rubygems.org' -gem 'json', '~> 2.8' +gem 'json' gem 'sequel', '~> 5.0' -gem 'rack', '~> 3.1' +gem 'rack', '~> 3.2' gem "concurrent-ruby" group :mysql, optional: true do - gem 'trilogy', '~> 2.9', platforms: [:ruby, :windows] + gem 'trilogy', '~> 2.10' end group :postgresql, optional: true do - gem 'pg', '~> 1.5', platforms: [:ruby, :windows] - gem 'sequel_pg', '~> 1.6', platforms: :ruby, require: false + gem 'pg', '~> 1.5' + gem 'sequel_pg', '~> 1.17', require: 'sequel' +end + +group :iodine, optional: true do + gem "iodine", "~> 0.7", require: false end group :puma, optional: true do gem 'puma', '~> 7.0', require: false end + diff --git a/frameworks/Ruby/rack-sequel/Gemfile.lock b/frameworks/Ruby/rack-sequel/Gemfile.lock index 7f052698932..1c3070f34cc 100644 --- a/frameworks/Ruby/rack-sequel/Gemfile.lock +++ b/frameworks/Ruby/rack-sequel/Gemfile.lock @@ -1,22 +1,24 @@ GEM remote: https://rubygems.org/ specs: - bigdecimal (3.3.1) + bigdecimal (4.0.1) concurrent-ruby (1.3.5) - json (2.16.0) - nio4r (2.7.4) - pg (1.6.2) - pg (1.6.2-x86_64-darwin) - pg (1.6.2-x86_64-linux) - puma (7.0.2) + iodine (0.7.58) + json (2.18.0) + nio4r (2.7.5) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) + puma (7.2.0) nio4r (~> 2.0) - rack (3.2.0) - sequel (5.97.0) + rack (3.2.5) + sequel (5.100.0) bigdecimal - sequel_pg (1.17.2) + sequel_pg (1.18.2) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) - trilogy (2.9.0) + trilogy (2.10.0) + bigdecimal PLATFORMS ruby @@ -25,13 +27,14 @@ PLATFORMS DEPENDENCIES concurrent-ruby - json (~> 2.8) + iodine (~> 0.7) + json pg (~> 1.5) puma (~> 7.0) - rack (~> 3.1) + rack (~> 3.2) sequel (~> 5.0) - sequel_pg (~> 1.6) - trilogy (~> 2.9) + sequel_pg (~> 1.17) + trilogy (~> 2.10) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/rack-sequel/benchmark_config.json b/frameworks/Ruby/rack-sequel/benchmark_config.json index 15763639c4c..c62366b12a9 100644 --- a/frameworks/Ruby/rack-sequel/benchmark_config.json +++ b/frameworks/Ruby/rack-sequel/benchmark_config.json @@ -6,7 +6,6 @@ "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -19,7 +18,45 @@ "os": "Linux", "database_os": "Linux", "display_name": "rack-sequel [puma, mysql]", - "versus": "rack-puma-mri", + "notes": "" + }, + "iodine": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "rack", + "language": "Ruby", + "orm": "Micro", + "platform": "Rack", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack-sequel [iodine, mysql]", + "versus": "rack-iodine", + "notes": "" + }, + "iodine-postgres": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "rack", + "language": "Ruby", + "orm": "Micro", + "platform": "Rack", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack-sequel [iodine, postgres]", + "versus": "rack-iodine", "notes": "" }, "postgres": { @@ -39,7 +76,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "rack-sequel [puma, postgres]", - "versus": null, + "versus": "rack", "notes": "" } } diff --git a/frameworks/Ruby/rack-sequel/boot.rb b/frameworks/Ruby/rack-sequel/boot.rb deleted file mode 100644 index 91594951944..00000000000 --- a/frameworks/Ruby/rack-sequel/boot.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true -require 'bundler/setup' - -SEQUEL_NO_ASSOCIATIONS = true - -Bundler.require(:default) # Load core modules - -def connect(dbtype) - Bundler.require(dbtype) # Load database-specific modules - - opts = {} - - if dbtype == :mysql - adapter = 'trilogy' - opts[:ssl] = true - opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY - opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 - else - adapter = 'postgresql' - end - - # Determine threading/thread pool size and timeout - if defined?(Puma) - opts[:max_connections] = ENV.fetch('MAX_THREADS') - opts[:pool_timeout] = 10 - else - opts[:max_connections] = 512 - end - - Sequel.connect \ - '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { - adapter: adapter, - host: 'tfb-database', - database: 'hello_world', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass' - }, opts -end - -DB = connect ENV.fetch('DBTYPE').to_sym - -# Define ORM models -class World < Sequel::Model(:World) - def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql - - def self.batch_update(worlds) - if DB.database_type == :mysql - worlds.map(&:save_changes) - else - ids = [] - sql = String.new("UPDATE world SET randomnumber = CASE id ") - worlds.each do |world| - sql << "when #{world[:id]} then #{world[:randomnumber]} " - ids << world[:id] - end - sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" - DB.run(sql) - end - end -end - -class Fortune < Sequel::Model(:Fortune) - # Allow setting id to zero (0) per benchmark requirements - unrestrict_primary_key -end - -[World, Fortune].each(&:freeze) -DB.freeze diff --git a/frameworks/Ruby/rack-sequel/config.ru b/frameworks/Ruby/rack-sequel/config.ru index 8fceb7c06fc..9917d37585b 100644 --- a/frameworks/Ruby/rack-sequel/config.ru +++ b/frameworks/Ruby/rack-sequel/config.ru @@ -1,4 +1,5 @@ -require_relative 'boot' +# frozen_string_literal: true require_relative 'hello_world' + use Rack::ContentLength run HelloWorld.new diff --git a/frameworks/Ruby/rack-sequel/config/auto_tune.rb b/frameworks/Ruby/rack-sequel/config/auto_tune.rb deleted file mode 100644 index 495956c0700..00000000000 --- a/frameworks/Ruby/rack-sequel/config/auto_tune.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - fail "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - (Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $0 == __FILE__ diff --git a/frameworks/Ruby/rack-sequel/db.rb b/frameworks/Ruby/rack-sequel/db.rb new file mode 100644 index 00000000000..5e6d6289500 --- /dev/null +++ b/frameworks/Ruby/rack-sequel/db.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +SEQUEL_NO_ASSOCIATIONS = true + +def connect(dbtype) + Bundler.require(dbtype) # Load database-specific modules + + opts = {} + + if dbtype == :mysql + adapter = 'trilogy' + opts[:ssl] = true + opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY + opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 + else + adapter = 'postgresql' + end + + # Determine threading/thread pool size and timeout + if defined?(Puma) + opts[:max_connections] = ENV.fetch('MAX_THREADS') + opts[:pool_timeout] = 10 + else + opts[:max_connections] = 512 + end + + Sequel.connect \ + '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { + adapter: adapter, + host: 'tfb-database', + database: 'hello_world', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' + }, opts +end + +DB = connect ENV.fetch('DBTYPE').to_sym + +# Define ORM models +class World < Sequel::Model(:World) + def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql + + def self.batch_update(worlds) + if DB.database_type == :mysql + worlds.map(&:save_changes) + else + ids = [] + sql = String.new("UPDATE world SET randomnumber = CASE id ") + worlds.each do |world| + sql << "when #{world[:id]} then #{world[:randomnumber]} " + ids << world[:id] + end + sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" + DB.run(sql) + end + end +end + +class Fortune < Sequel::Model(:Fortune) + # Allow setting id to zero (0) per benchmark requirements + unrestrict_primary_key +end + +[World, Fortune].each(&:freeze) +DB.freeze diff --git a/frameworks/Ruby/rack-sequel/hello_world.rb b/frameworks/Ruby/rack-sequel/hello_world.rb index 9b496788da6..af99b0a22da 100644 --- a/frameworks/Ruby/rack-sequel/hello_world.rb +++ b/frameworks/Ruby/rack-sequel/hello_world.rb @@ -1,4 +1,8 @@ # frozen_string_literal: true +require 'bundler/setup' +Bundler.require(:default) # Load core modules + +require_relative 'db' require 'time' # Our Rack application to be executed by rackup @@ -8,8 +12,8 @@ class HelloWorld ALL_IDS = ID_RANGE.to_a QUERIES_MIN = 1 QUERIES_MAX = 500 + CONTENT_TYPE = 'Content-Type' - CONTENT_LENGTH = 'Content-Length' JSON_TYPE = 'application/json' HTML_TYPE = 'text/html; charset=utf-8' PLAINTEXT_TYPE = 'text/plain' @@ -44,26 +48,26 @@ def queries(env) def fortunes fortunes = Fortune.all - fortunes << Fortune.new( - id: 0, - message: 'Additional fortune added at request time.' - ) + + fortune = Fortune.new + fortune.id = 0 + fortune.message = -"Additional fortune added at request time." + fortunes << fortune + fortunes.sort_by!(&:message) html = String.new(<<~'HTML') - - Fortunes - - + + Fortunes + - - - - - - +
idmessage
+ + + + HTML fortunes.each do |fortune| @@ -77,7 +81,6 @@ def fortunes html << <<~'HTML'
idmessage
- HTML @@ -104,22 +107,22 @@ def call(env) case env['PATH_INFO'] when '/json' # Test type 1: JSON serialization - respond JSON_TYPE, { message: 'Hello, World!' }.to_json + respond JSON_TYPE, JSON.generate({ message: -'Hello, World!' }) when '/db' # Test type 2: Single database query - respond JSON_TYPE, db.to_json + respond JSON_TYPE, JSON.generate(db) when '/queries' # Test type 3: Multiple database queries - respond JSON_TYPE, queries(env).to_json + respond JSON_TYPE, JSON.generate(queries(env)) when '/fortunes' # Test type 4: Fortunes respond HTML_TYPE, fortunes when '/updates' # Test type 5: Database updates - respond JSON_TYPE, updates(env).to_json + respond JSON_TYPE, JSON.generate(updates(env)) when '/plaintext' # Test type 6: Plaintext - respond PLAINTEXT_TYPE, 'Hello, World!' + respond PLAINTEXT_TYPE, -'Hello, World!' end end @@ -128,21 +131,21 @@ def call(env) def respond(content_type, body) [ 200, - headers(content_type, body), + headers(content_type), [body] ] end if defined?(Puma) - def headers(content_type, _) + def headers(content_type) { CONTENT_TYPE => content_type, SERVER => SERVER_STRING, - DATE => Time.now.utc.httpdate + DATE => Time.now.httpdate } end else - def headers(content_type, _) + def headers(content_type) { CONTENT_TYPE => content_type, SERVER => SERVER_STRING diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-iodine-postgres.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-iodine-postgres.dockerfile new file mode 100644 index 00000000000..4e0b1f07914 --- /dev/null +++ b/frameworks/Ruby/rack-sequel/rack-sequel-iodine-postgres.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:4.0 + +ADD ./ /rack-sequel + +WORKDIR /rack-sequel + +ENV RUBY_YJIT_ENABLE=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +RUN bundle config set with 'postgresql iodine' +RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile + +ENV DBTYPE=postgresql + +EXPOSE 8080 + +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-iodine.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-iodine.dockerfile new file mode 100644 index 00000000000..5f3e70b2a8b --- /dev/null +++ b/frameworks/Ruby/rack-sequel/rack-sequel-iodine.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:4.0 + +ADD ./ /rack-sequel + +WORKDIR /rack-sequel + +ENV RUBY_YJIT_ENABLE=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +RUN bundle config set with 'mysql iodine' +RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile + +ENV DBTYPE=mysql + +EXPOSE 8080 + +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile index a1cf4826f9c..af2a839d8d6 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile @@ -1,10 +1,11 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ADD ./ /rack-sequel WORKDIR /rack-sequel ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -16,9 +17,10 @@ RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile ENV DBTYPE=postgresql -ENV WEB_CONCURRENCY=auto -ENV MAX_THREADS=5 +ENV MIN_THREADS=8 +ENV MAX_THREADS=8 EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production +CMD export WEB_CONCURRENCY=auto && \ + bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile index bf8a4a28f13..d5c3548bd18 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile @@ -1,10 +1,11 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ADD ./ /rack-sequel WORKDIR /rack-sequel ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -16,9 +17,10 @@ RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile ENV DBTYPE=mysql -ENV WEB_CONCURRENCY=auto -ENV MAX_THREADS=5 +ENV MIN_THREADS=8 +ENV MAX_THREADS=8 EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production +CMD export WEB_CONCURRENCY=auto && \ + bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack/.dockerignore b/frameworks/Ruby/rack/.dockerignore deleted file mode 100644 index b844b143d22..00000000000 --- a/frameworks/Ruby/rack/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -Gemfile.lock diff --git a/frameworks/Ruby/rack/Gemfile b/frameworks/Ruby/rack/Gemfile index 47ec614226a..573ba3726c3 100644 --- a/frameworks/Ruby/rack/Gemfile +++ b/frameworks/Ruby/rack/Gemfile @@ -6,14 +6,19 @@ source 'https://rubygems.org' puts "Platform: #{Gem::Platform.local}" gem 'rack', '~> 3.0' -gem 'connection_pool', '~> 2.4' -gem 'jdbc-postgres', '~> 42.2', platforms: :jruby, require: 'jdbc/postgres' -gem 'json', '~> 2.10' -gem 'pg', '~> 1.5', platforms: %i[ruby windows] -gem 'sequel' -gem 'sequel_pg', platforms: %i[ruby windows] +gem 'connection_pool' +gem 'json' gem 'tzinfo-data', '1.2023.3' +platforms :ruby, :windows do + gem 'pg', '~> 1.5', platforms: %i[ruby windows] +end + +platforms :jruby do + gem 'jdbc-postgres', '~> 42.2', require: 'jdbc/postgres' + gem 'sequel' +end + group :falcon, optional: true do gem 'falcon', '~> 0.52', platforms: %i[ruby windows] end @@ -27,7 +32,7 @@ group :itsi, optional: true do end group :passenger, optional: true do - gem 'logger' # required by passenger on Ruby 3.5 + gem 'logger' # required by passenger on Ruby 4.0 gem 'passenger', '~> 6.1', platforms: [:ruby, :windows], require: false end diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index 7028b8ed05d..8e569698daa 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -2,59 +2,59 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - async (2.34.0) + async (2.36.0) console (~> 1.29) fiber-annotation io-event (~> 1.11) metrics (~> 0.12) traces (~> 0.18) - async-container (0.27.7) + async-container (0.30.0) async (~> 2.22) - async-container-supervisor (0.9.1) + async-container-supervisor (0.9.3) async-service io-endpoint memory (~> 0.7) memory-leak (~> 0.5) process-metrics - async-http (0.92.1) + async-http (0.94.2) async (>= 2.10.2) async-pool (~> 0.11) io-endpoint (~> 0.14) io-stream (~> 0.6) metrics (~> 0.12) - protocol-http (~> 0.49) - protocol-http1 (~> 0.30) + protocol-http (~> 0.58) + protocol-http1 (~> 0.36) protocol-http2 (~> 0.22) protocol-url (~> 0.2) traces (~> 0.10) async-http-cache (0.4.6) async-http (~> 0.56) - async-pool (0.11.0) + async-pool (0.11.1) async (>= 2.0) - async-service (0.14.4) + async-service (0.19.1) async - async-container (~> 0.16) + async-container (~> 0.29) string-format (~> 0.2) bake (0.24.1) bigdecimal samovar (~> 2.1) - bigdecimal (3.1.9) + bigdecimal (4.0.1) concurrent-ruby (1.3.5) - connection_pool (2.5.0) - console (1.34.2) + connection_pool (3.0.2) + console (1.34.3) fiber-annotation fiber-local (~> 1.1) json - falcon (0.52.4) + falcon (0.54.2) async async-container (~> 0.20) async-container-supervisor (~> 0.6) async-http (~> 0.75) async-http-cache (~> 0.4) - async-service (~> 0.10) + async-service (~> 0.19) bundler localhost (~> 1.1) - openssl (~> 3.0) + openssl (>= 3.0) protocol-http (~> 0.31) protocol-rack (~> 0.7) samovar (~> 2.3) @@ -62,24 +62,24 @@ GEM fiber-local (1.1.0) fiber-storage fiber-storage (1.0.1) - io-endpoint (0.15.2) + io-endpoint (0.17.2) io-event (1.14.2) - io-stream (0.11.0) + io-stream (0.11.1) iodine (0.7.58) - itsi (0.2.18) - itsi-scheduler (~> 0.2.18) - itsi-server (~> 0.2.18) - itsi-scheduler (0.2.18) + itsi (0.2.21) + itsi-scheduler (= 0.2.21) + itsi-server (= 0.2.21) + itsi-scheduler (0.2.21) rb_sys (~> 0.9.91) - itsi-server (0.2.18) + itsi-server (0.2.21) json (~> 2) prism (~> 1.4) rack (>= 1.6) rb_sys (~> 0.9.91) - json (2.16.0) + json (2.18.1) language_server-protocol (3.17.0.4) lint_roller (1.1.0) - localhost (1.6.0) + localhost (1.7.0) logger (1.6.6) mapping (1.1.3) memory (0.12.0) @@ -89,52 +89,53 @@ GEM memory-leak (0.7.0) metrics (0.15.0) msgpack (1.8.0) - nio4r (2.7.4) - openssl (3.3.2) + nio4r (2.7.5) + openssl (4.0.0) parallel (1.26.3) parser (3.3.7.1) ast (~> 2.4.1) racc - passenger (6.1.0) + passenger (6.1.1) rack (>= 1.6.13) rackup (>= 1.0.1) rake (>= 12.3.3) - pg (1.6.2-arm64-darwin) - pg (1.6.2-x86_64-darwin) - pg (1.6.2-x86_64-linux) + pg (1.6.3) + pg (1.6.3-arm64-darwin) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) pitchfork (0.17.0) logger rack (>= 2.0) - prism (1.4.0) - process-metrics (0.7.0) + prism (1.9.0) + process-metrics (0.8.0) console (~> 1.8) json (~> 2) samovar (~> 2.1) protocol-hpack (1.5.1) - protocol-http (0.55.0) - protocol-http1 (0.35.2) - protocol-http (~> 0.22) - protocol-http2 (0.23.0) + protocol-http (0.59.0) + protocol-http1 (0.37.0) + protocol-http (~> 0.58) + protocol-http2 (0.24.0) protocol-hpack (~> 1.4) protocol-http (~> 0.47) - protocol-rack (0.16.0) + protocol-rack (0.21.1) io-stream (>= 0.10) - protocol-http (~> 0.43) + protocol-http (~> 0.58) rack (>= 1.0) protocol-url (0.4.0) - puma (7.1.0) + puma (7.2.0) nio4r (~> 2.0) racc (1.8.1) - rack (3.2.4) + rack (3.2.5) rack-test (2.2.0) rack (>= 1.3) - rackup (2.2.1) + rackup (2.3.1) rack (>= 3) rainbow (3.1.1) - rake (13.3.0) - rake-compiler-dock (1.9.1) - rb_sys (0.9.117) - rake-compiler-dock (= 1.9.1) + rake (13.3.1) + rake-compiler-dock (1.11.0) + rb_sys (0.9.124) + rake-compiler-dock (= 1.11.0) regexp_parser (2.10.0) rubocop (1.73.2) json (~> 2.3) @@ -153,11 +154,6 @@ GEM samovar (2.4.1) console (~> 1.0) mapping (~> 1.0) - sequel (5.90.0) - bigdecimal - sequel_pg (1.17.1) - pg (>= 0.18.0, != 1.2.0) - sequel (>= 4.38.0) string-format (0.2.0) traces (0.18.2) tzinfo (2.0.6) @@ -170,16 +166,17 @@ GEM PLATFORMS arm64-darwin-24 + ruby x86_64-darwin-23 x86_64-linux DEPENDENCIES - connection_pool (~> 2.4) + connection_pool falcon (~> 0.52) iodine (~> 0.7) itsi jdbc-postgres (~> 42.2) - json (~> 2.10) + json logger passenger (~> 6.1) pg (~> 1.5) @@ -189,8 +186,7 @@ DEPENDENCIES rack-test rubocop sequel - sequel_pg tzinfo-data (= 1.2023.3) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/rack/benchmark_config.json b/frameworks/Ruby/rack/benchmark_config.json index 031e00dc5e9..1e439f626c4 100644 --- a/frameworks/Ruby/rack/benchmark_config.json +++ b/frameworks/Ruby/rack/benchmark_config.json @@ -148,6 +148,27 @@ "database_os": "Linux", "display_name": "rack [pitchfork]", "notes": "" + }, + "zjit": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "orm": "raw", + "database": "Postgres", + "framework": "rack", + "language": "Ruby", + "platform": "Mri", + "webserver": "Pitchfork", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack [puma, zjit]", + "notes": "" } } ] diff --git a/frameworks/Ruby/rack/config/itsi.rb b/frameworks/Ruby/rack/config/itsi.rb index d0dd0992dc1..e4452465217 100644 --- a/frameworks/Ruby/rack/config/itsi.rb +++ b/frameworks/Ruby/rack/config/itsi.rb @@ -9,5 +9,5 @@ num_workers, num_threads = auto_tune workers num_workers -threads num_threads +threads ENV.fetch('MAX_THREADS').to_i fiber_scheduler false diff --git a/frameworks/Ruby/rack/config/pitchfork.rb b/frameworks/Ruby/rack/config/pitchfork.rb index 9cf3d92dfbe..b7f0cb958de 100644 --- a/frameworks/Ruby/rack/config/pitchfork.rb +++ b/frameworks/Ruby/rack/config/pitchfork.rb @@ -1,13 +1,7 @@ # frozen_string_literal: true -require_relative 'auto_tune' -require 'sequel' -num_workers, = auto_tune +require 'etc' -worker_processes num_workers - -before_fork do |_server| - Sequel::DATABASES.each(&:disconnect) -end +worker_processes (Etc.nprocessors * 1.5).to_i listen "/tmp/.sock", :backlog => 4096 diff --git a/frameworks/Ruby/rack/config/puma.rb b/frameworks/Ruby/rack/config/puma.rb index 18a4851a761..04f6723233d 100644 --- a/frameworks/Ruby/rack/config/puma.rb +++ b/frameworks/Ruby/rack/config/puma.rb @@ -1,7 +1,4 @@ -if ENV.fetch('WEB_CONCURRENCY') == 'auto' - before_fork do - Sequel::DATABASES.each(&:disconnect) - end +if ENV.fetch('WEB_CONCURRENCY').to_i > 1 else workers ENV.fetch('WEB_CONCURRENCY') require 'concurrent/utility/processor_counter' diff --git a/frameworks/Ruby/rack/db.rb b/frameworks/Ruby/rack/db.rb new file mode 100644 index 00000000000..bec8d8ad038 --- /dev/null +++ b/frameworks/Ruby/rack/db.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'pg' +require 'connection_pool' + +def connect(url) + if defined?(Puma) || defined?(Itsi) + max_connections = ENV.fetch('MAX_THREADS') + elsif defined?(Iodine) + max_connections = ENV.fetch('THREADS') + else + max_connections = 512 + end + ConnectionPool.new(size: max_connections, timeout: 5) do + PGConnection.new(url) + end +end + +class PGConnection + attr_reader :connection + + def initialize(connection_string) + @connection = PG::Connection.new(connection_string) + @connection.set_error_verbosity(PG::PQERRORS_VERBOSE) + @connection.prepare('select_world', 'SELECT id, randomNumber FROM world WHERE id = $1') + end + + def select_world(id) + @connection.exec_prepared('select_world', [id]).first + end + + def select_fortunes + @connection.exec('SELECT id, message FROM fortune') + end + + def exec(query) + @connection.exec(query) + end +end diff --git a/frameworks/Ruby/rack/db_jruby.rb b/frameworks/Ruby/rack/db_jruby.rb new file mode 100644 index 00000000000..d930e106fc5 --- /dev/null +++ b/frameworks/Ruby/rack/db_jruby.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'sequel' + +def connect(url) + max_connections = ENV['MAX_THREADS'].to_i + JDBCConnection.new("jdbc:" + url, max_connections: max_connections) +end + +class JDBCConnection + attr_reader :connection + + def initialize(connection_string, max_connections:) + @connection = Sequel.connect(connection_string, max_connections: max_connections) + @world_select = @connection['SELECT id, randomNumber FROM World WHERE id = ?', :$id].prepare(:select, :select_by_id) + @fortune_select = @connection['SELECT id, message FROM Fortune'].prepare(:select, :select_all) + end + + def select_world(id) + @world_select.call(id: id).first.transform_keys(&:to_s) + end + + def select_fortunes + @fortune_select.call.map { it.transform_keys(&:to_s) } + end + + def exec(query) + @connection[query].update + end + + def with + yield(self) + end +end diff --git a/frameworks/Ruby/rack/hello_world.rb b/frameworks/Ruby/rack/hello_world.rb index 9944ac45d40..f7c9cd764bb 100644 --- a/frameworks/Ruby/rack/hello_world.rb +++ b/frameworks/Ruby/rack/hello_world.rb @@ -2,97 +2,58 @@ # Our Rack application to be executed by rackup -require_relative 'pg_db' +if RUBY_PLATFORM == 'java' + require_relative 'db_jruby' +else + require_relative 'db' +end require_relative 'config/auto_tune' require 'rack' require 'json' +require 'time' require 'erb' -if RUBY_PLATFORM == 'java' - DEFAULT_DATABASE_URL = 'jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass' -else - DEFAULT_DATABASE_URL = 'postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass' -end +DATABASE_URL = 'postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass' +$db = connect(DATABASE_URL) class HelloWorld QUERY_RANGE = (1..10_000).freeze # range of IDs in the Fortune DB ALL_IDS = QUERY_RANGE.to_a # enumeration of all the IDs in fortune DB MIN_QUERIES = 1 # min number of records that can be retrieved MAX_QUERIES = 500 # max number of records that can be retrieved + CONTENT_TYPE = 'Content-Type' - CONTENT_LENGTH = 'Content-Length' JSON_TYPE = 'application/json' HTML_TYPE = 'text/html; charset=utf-8' PLAINTEXT_TYPE = 'text/plain' DATE = 'Date' SERVER = 'Server' SERVER_STRING = 'Rack' - TEMPLATE_PREFIX = ' - - - Fortunes - - - - - - - ' - TEMPLATE_POSTFIX = '
idmessage
- - ' - - def initialize - if defined?(Puma) - max_connections = ENV.fetch('MAX_THREADS') - elsif defined?(Itsi) - require_relative 'config/auto_tune' - _num_workers, num_threads = auto_tune - max_connections = num_threads - else - max_connections = 512 - end - @db = PgDb.new(DEFAULT_DATABASE_URL, max_connections) - end - - def fortunes - fortunes = @db.select_fortunes - fortunes << { id: 0, message: 'Additional fortune added at request time.' } - fortunes.sort_by! { |item| item[:message] } - buffer = String.new - buffer << TEMPLATE_PREFIX - - fortunes.each do |item| - buffer << "#{item[:id]}#{ERB::Escape.html_escape(item[:message])}" - end - buffer << TEMPLATE_POSTFIX - end def call(env) case env['PATH_INFO'] when '/json' # Test type 1: JSON serialization respond JSON_TYPE, - { message: 'Hello, World!' }.to_json + JSON.generate({ message: -'Hello, World!' }) when '/db' # Test type 2: Single database query - respond JSON_TYPE, @db.select_random_world.to_json + id = random_id + respond JSON_TYPE, JSON.generate($db.with{ _1.select_world(id) }) when '/queries' # Test type 3: Multiple database queries - params = Rack::Utils.parse_query(env['QUERY_STRING']) - queries = params['queries'] - respond JSON_TYPE, @db.select_worlds(queries).to_json + queries = bounded_queries(env) + respond JSON_TYPE, JSON.generate(select_worlds(queries)) when '/fortunes' # Test type 4: Fortunes respond HTML_TYPE, fortunes when '/updates' # Test type 5: Database updates - params = Rack::Utils.parse_query(env['QUERY_STRING']) - queries = params['queries'] - respond JSON_TYPE, @db.update_worlds(queries).to_json + queries = bounded_queries(env) + respond JSON_TYPE, JSON.generate(update_worlds(queries)) when '/plaintext' # Test type 6: Plaintext - respond PLAINTEXT_TYPE, 'Hello, World!' + respond PLAINTEXT_TYPE, -'Hello, World!' end end @@ -101,25 +62,91 @@ def call(env) def respond(content_type, body) [ 200, - headers(content_type, body), + headers(content_type), [body] ] end - if defined?(Falcon) || defined?(Puma) - def headers(content_type, _) + if defined?(Puma) || defined?(Falcon) + def headers(content_type) { CONTENT_TYPE => content_type, SERVER => SERVER_STRING, - DATE => Time.now.utc.httpdate + DATE => Time.now.httpdate } end else - def headers(content_type, _) + def headers(content_type) { CONTENT_TYPE => content_type, SERVER => SERVER_STRING } end end + + def fortunes + fortunes = $db.with(&:select_fortunes).map(&:to_h) + fortunes << { 'id' => 0, 'message' => -'Additional fortune added at request time.' } + fortunes.sort_by! { |item| item['message'] } + + html = String.new(<<~'HTML') + + + + Fortunes + + + + + + + + + + HTML + + fortunes.each do |item| + html << "" + end + + html << <<~'HTML' +
idmessage
#{item['id']}#{ERB::Escape.html_escape(item['message'])}
+ + + HTML + end + + def update_worlds(count) + results = select_worlds(count) + ids = [] + sql = String.new("UPDATE world SET randomnumber = CASE id ") + results.each do |r| + r['randomnumber'] = random_id + ids << r['id'] + sql << "when #{r['id']} then #{r['randomnumber']} " + end + sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" + $db.with{ _1.exec(sql) } + results + end + + def select_worlds(count) + ids = ALL_IDS.sample(count) + $db.with do |conn| + ids.map do |id| + conn.select_world(id) + end + end + end + + def random_id + Random.rand(QUERY_RANGE) + end + + def bounded_queries(env) + params = Rack::Utils.parse_query(env['QUERY_STRING']) + + queries = params['queries'].to_i + queries.clamp(MIN_QUERIES, MAX_QUERIES) + end end diff --git a/frameworks/Ruby/rack/pg_db.rb b/frameworks/Ruby/rack/pg_db.rb deleted file mode 100644 index c7b2c78cc6d..00000000000 --- a/frameworks/Ruby/rack/pg_db.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -require 'sequel' - -if RUBY_PLATFORM == 'java' - require 'jdbc/postgres' - Jdbc::Postgres.load_driver -end - -class PgDb - QUERY_RANGE = (1..10_000).freeze # range of IDs in the Fortune DB - ALL_IDS = QUERY_RANGE.to_a # enumeration of all the IDs in fortune DB - MIN_QUERIES = 1 # min number of records that can be retrieved - MAX_QUERIES = 500 # max number of records that can be retrieved - - attr_reader :connection - - def initialize(connection_string = nil, max_connections = 512) - @connection = Sequel.connect(connection_string, max_connections: max_connections) - Sequel.extension :fiber_concurrency if defined?(Falcon) - - prepare_statements - end - - def prepare_statements - @world_select = @connection['SELECT id, randomNumber FROM World WHERE id = ?', :$id].prepare(:select, :select_by_id) - @world_update = @connection['UPDATE World SET randomNumber = ? WHERE id = ?', :$random_number, :$id].prepare(:update, - :update_by_id) - @fortune_select = @connection['SELECT id, message FROM Fortune'].prepare(:select, :select_all) - end - - def select_random_world - select_world(random_id) - end - - def select_world(id) - @world_select.call(id: id).first - end - - def validate_count(count) - count = count.to_i - count.clamp(MIN_QUERIES, MAX_QUERIES) - end - - def select_promises(count) - count = validate_count(count) - ALL_IDS.sample(count).map do |id| - @connection.synchronize do - @connection['SELECT id, randomNumber FROM World WHERE id = ?', id].async.first - end - end - end - - def select_worlds(count) - count = validate_count(count) - ALL_IDS.sample(count).map do |id| - @world_select.call(id: id).first - end - end - - def select_worlds_async(count) - promises = select_promises(count) - promises.map(&:to_hash) - end - - def update_worlds(count, async = false) - results = if async - select_worlds_async(count) - else - select_worlds(count) - end - ids = [] - sql = String.new("UPDATE world SET randomnumber = CASE id ") - results.each do |r| - r[:randomnumber] = random_id - ids << r[:id] - sql << "when #{r[:id]} then #{r[:randomnumber]} " - end - sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" - @connection[sql].update - results - end - - def select_fortunes - @fortune_select.call - end - - def random_id - Random.rand(QUERY_RANGE) - end -end diff --git a/frameworks/Ruby/rack/rack-falcon.dockerfile b/frameworks/Ruby/rack/rack-falcon.dockerfile index 608fb7a39a9..eb737be8bd4 100644 --- a/frameworks/Ruby/rack/rack-falcon.dockerfile +++ b/frameworks/Ruby/rack/rack-falcon.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/rack/rack-iodine.dockerfile b/frameworks/Ruby/rack/rack-iodine.dockerfile index 26f65700e15..9acc3d4ceff 100644 --- a/frameworks/Ruby/rack/rack-iodine.dockerfile +++ b/frameworks/Ruby/rack/rack-iodine.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 @@ -17,6 +17,8 @@ RUN bundle install --jobs=8 COPY . . +ENV THREADS=2 + EXPOSE 8080 -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) +CMD bundle exec iodine -p 8080 -w $(nproc) diff --git a/frameworks/Ruby/rack/rack-itsi.dockerfile b/frameworks/Ruby/rack/rack-itsi.dockerfile index 952ac7ccdad..7905535cb3f 100644 --- a/frameworks/Ruby/rack/rack-itsi.dockerfile +++ b/frameworks/Ruby/rack/rack-itsi.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.5-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 @@ -19,6 +19,8 @@ RUN bundle install --jobs=8 COPY . . +ENV MAX_THREADS=5 + EXPOSE 8080 CMD bundle exec itsi start -C config/itsi.rb --bind "http://tfb-server:8080" diff --git a/frameworks/Ruby/rack/rack-passenger.dockerfile b/frameworks/Ruby/rack/rack-passenger.dockerfile index 115f5740f1c..5b1eb1f2d5d 100644 --- a/frameworks/Ruby/rack/rack-passenger.dockerfile +++ b/frameworks/Ruby/rack/rack-passenger.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/rack/rack-pitchfork.dockerfile b/frameworks/Ruby/rack/rack-pitchfork.dockerfile index 1546e882b4e..91e17cd9d2a 100644 --- a/frameworks/Ruby/rack/rack-pitchfork.dockerfile +++ b/frameworks/Ruby/rack/rack-pitchfork.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 diff --git a/frameworks/Ruby/rack/rack-zjit.dockerfile b/frameworks/Ruby/rack/rack-zjit.dockerfile new file mode 100644 index 00000000000..585eed731bf --- /dev/null +++ b/frameworks/Ruby/rack/rack-zjit.dockerfile @@ -0,0 +1,27 @@ +FROM ruby:4.0 + +ENV RUBY_ZJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +WORKDIR /rack + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'puma' +RUN bundle install --jobs=8 + +COPY . . + +ENV MIN_THREADS=5 +ENV MAX_THREADS=5 + +EXPOSE 8080 + +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index dea3795b187..36a4b30e2da 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -1,6 +1,7 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -17,9 +18,10 @@ RUN bundle install --jobs=8 COPY . . -ENV WEB_CONCURRENCY=auto +ENV MIN_THREADS=5 ENV MAX_THREADS=5 EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rage-sequel/.gitignore b/frameworks/Ruby/rage-sequel/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/rage-sequel/Gemfile b/frameworks/Ruby/rage-sequel/Gemfile index 35b2df23c98..6357a5204fb 100644 --- a/frameworks/Ruby/rage-sequel/Gemfile +++ b/frameworks/Ruby/rage-sequel/Gemfile @@ -1,8 +1,7 @@ source "https://rubygems.org" -gem "rage-rb", "~> 1.17.0" +gem "rage-rb", "~> 1.19" gem "pg", "~> 1.0" gem 'sequel', '~> 5.0' -gem 'sequel_pg', '~> 1.6', platforms: :ruby, require: false -gem 'logger' # required for ruby 3.5 +gem 'sequel_pg', '~> 1.17', require: 'sequel' diff --git a/frameworks/Ruby/rage-sequel/Gemfile.lock b/frameworks/Ruby/rage-sequel/Gemfile.lock index fb432a9f4d3..488603bf512 100644 --- a/frameworks/Ruby/rage-sequel/Gemfile.lock +++ b/frameworks/Ruby/rage-sequel/Gemfile.lock @@ -1,40 +1,40 @@ GEM remote: https://rubygems.org/ specs: - bigdecimal (3.3.1) + bigdecimal (4.0.1) logger (1.7.0) - pg (1.6.2) - pg (1.6.2-x86_64-darwin) - rack (2.2.20) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + rack (3.2.4) rack-test (2.2.0) rack (>= 1.3) rage-iodine (4.4.0) - rage-rb (1.17.1) - rack (~> 2.0) + rage-rb (1.19.2) + logger + rack (< 4) rack-test (~> 2.1) rage-iodine (~> 4.3) rake (>= 12.0) thor (~> 1.0) zeitwerk (~> 2.6) - rake (13.2.1) - sequel (5.97.0) + rake (13.3.1) + sequel (5.100.0) bigdecimal - sequel_pg (1.17.2) + sequel_pg (1.18.2) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) - thor (1.3.2) - zeitwerk (2.7.2) + thor (1.5.0) + zeitwerk (2.7.4) PLATFORMS ruby x86_64-darwin-20 DEPENDENCIES - logger pg (~> 1.0) - rage-rb (~> 1.17.0) + rage-rb (~> 1.19) sequel (~> 5.0) - sequel_pg (~> 1.6) + sequel_pg (~> 1.17) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/rage-sequel/README.md b/frameworks/Ruby/rage-sequel/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb b/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb index 4765293093d..a1c091bbeae 100644 --- a/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb +++ b/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb @@ -26,7 +26,11 @@ def queries def fortunes records = Fortune.all - records << Fortune.new(id: 0, message: "Additional fortune added at request time.") + fortune = Fortune.new + fortune.id = 0 + fortune.message = "Additional fortune added at request time." + records << fortune + records.sort_by!(&:message) render plain: FORTUNES_TEMPLATE.result(binding) diff --git a/frameworks/Ruby/rage-sequel/benchmark_config.json b/frameworks/Ruby/rage-sequel/benchmark_config.json old mode 100755 new mode 100644 index 4cbe6d248f4..ffa2421bfaa --- a/frameworks/Ruby/rage-sequel/benchmark_config.json +++ b/frameworks/Ruby/rage-sequel/benchmark_config.json @@ -21,7 +21,7 @@ "database_os": "Linux", "display_name": "Rage-Sequel", "notes": "", - "versus": "None" + "versus": "rack-sequel-iodine-postgres" } } ] diff --git a/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile b/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile index 68a57f4b52a..98d674203b8 100644 --- a/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile +++ b/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 EXPOSE 8080 WORKDIR /rage-sequel diff --git a/frameworks/Ruby/rage/.gitignore b/frameworks/Ruby/rage/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/rage/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/rage/Gemfile b/frameworks/Ruby/rage/Gemfile index f2a24ddb082..6c300d6323a 100644 --- a/frameworks/Ruby/rage/Gemfile +++ b/frameworks/Ruby/rage/Gemfile @@ -1,9 +1,9 @@ source "https://rubygems.org" -gem "rage-rb", "~> 1.17.0" +gem "rage-rb", "~> 1.19" gem "pg", "~> 1.0" -gem "activerecord", "~> 8.0.0", require: "active_record" +gem "activerecord", "~> 8.1.0", require: "active_record" # Build JSON APIs with ease # gem "alba" diff --git a/frameworks/Ruby/rage/Gemfile.lock b/frameworks/Ruby/rage/Gemfile.lock index f0bf4cd1dad..aa91a6bb41b 100644 --- a/frameworks/Ruby/rage/Gemfile.lock +++ b/frameworks/Ruby/rage/Gemfile.lock @@ -1,65 +1,68 @@ GEM remote: https://rubygems.org/ specs: - activemodel (8.0.2) - activesupport (= 8.0.2) - activerecord (8.0.2) - activemodel (= 8.0.2) - activesupport (= 8.0.2) + activemodel (8.1.2) + activesupport (= 8.1.2) + activerecord (8.1.2) + activemodel (= 8.1.2) + activesupport (= 8.1.2) timeout (>= 0.4.0) - activesupport (8.0.2) + activesupport (8.1.2) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) - base64 (0.2.0) - benchmark (0.4.0) - bigdecimal (3.1.9) - concurrent-ruby (1.3.5) - connection_pool (2.5.0) - drb (2.2.1) - i18n (1.14.7) + base64 (0.3.0) + bigdecimal (4.0.1) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + drb (2.2.3) + i18n (1.14.8) concurrent-ruby (~> 1.0) + json (2.18.0) logger (1.7.0) - minitest (5.25.5) - pg (1.6.2) - pg (1.6.2-x86_64-darwin) - rack (2.2.18) + minitest (6.0.1) + prism (~> 1.5) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + prism (1.8.0) + rack (3.2.4) rack-test (2.2.0) rack (>= 1.3) rage-iodine (4.4.0) - rage-rb (1.17.1) - rack (~> 2.0) + rage-rb (1.19.2) + logger + rack (< 4) rack-test (~> 2.1) rage-iodine (~> 4.3) rake (>= 12.0) thor (~> 1.0) zeitwerk (~> 2.6) - rake (13.2.1) + rake (13.3.1) securerandom (0.4.1) - thor (1.3.2) - timeout (0.4.3) + thor (1.5.0) + timeout (0.6.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - uri (1.0.3) - zeitwerk (2.7.1) + uri (1.1.1) + zeitwerk (2.7.4) PLATFORMS ruby x86_64-darwin-23 DEPENDENCIES - activerecord (~> 8.0.0) + activerecord (~> 8.1.0) pg (~> 1.0) - rage-rb (~> 1.17.0) + rage-rb (~> 1.19) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/rage/README.md b/frameworks/Ruby/rage/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Ruby/rage/benchmark_config.json b/frameworks/Ruby/rage/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Ruby/rage/config/initializers/activerecord.rb b/frameworks/Ruby/rage/config/initializers/activerecord.rb index 34a3b019a66..91eedbba681 100644 --- a/frameworks/Ruby/rage/config/initializers/activerecord.rb +++ b/frameworks/Ruby/rage/config/initializers/activerecord.rb @@ -6,3 +6,5 @@ puts "ActiveRecord pool size: #{pool_size}" ENV["DATABASE_URL"]="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?pool=#{pool_size}&reaping_frequency=0" + +ActiveRecord::Base.logger = nil diff --git a/frameworks/Ruby/rage/rage.dockerfile b/frameworks/Ruby/rage/rage.dockerfile index d70e975a853..86308ca2efc 100644 --- a/frameworks/Ruby/rage/rage.dockerfile +++ b/frameworks/Ruby/rage/rage.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 EXPOSE 8080 WORKDIR /rage diff --git a/frameworks/Ruby/rails/.gitignore b/frameworks/Ruby/rails/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/rails/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/rails/Gemfile b/frameworks/Ruby/rails/Gemfile index ec48c009fcb..b514e6a29de 100644 --- a/frameworks/Ruby/rails/Gemfile +++ b/frameworks/Ruby/rails/Gemfile @@ -5,7 +5,7 @@ gem 'redis', '~> 5.0' gem 'tzinfo-data' group :mysql, optional: true do - gem 'trilogy', '~> 2.8.1' + gem 'trilogy', '~> 2.10' end group :postgresql, optional: true do diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index c14a68a3c0e..4a7a9c6db03 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -1,31 +1,31 @@ GEM remote: https://rubygems.org/ specs: - action_text-trix (2.1.15) + action_text-trix (2.1.17) railties - actioncable (8.1.0) - actionpack (= 8.1.0) - activesupport (= 8.1.0) + actioncable (8.1.2) + actionpack (= 8.1.2) + activesupport (= 8.1.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.1.0) - actionpack (= 8.1.0) - activejob (= 8.1.0) - activerecord (= 8.1.0) - activestorage (= 8.1.0) - activesupport (= 8.1.0) + actionmailbox (8.1.2) + actionpack (= 8.1.2) + activejob (= 8.1.2) + activerecord (= 8.1.2) + activestorage (= 8.1.2) + activesupport (= 8.1.2) mail (>= 2.8.0) - actionmailer (8.1.0) - actionpack (= 8.1.0) - actionview (= 8.1.0) - activejob (= 8.1.0) - activesupport (= 8.1.0) + actionmailer (8.1.2) + actionpack (= 8.1.2) + actionview (= 8.1.2) + activejob (= 8.1.2) + activesupport (= 8.1.2) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.1.0) - actionview (= 8.1.0) - activesupport (= 8.1.0) + actionpack (8.1.2) + actionview (= 8.1.2) + activesupport (= 8.1.2) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) @@ -33,36 +33,36 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (8.1.0) + actiontext (8.1.2) action_text-trix (~> 2.1.15) - actionpack (= 8.1.0) - activerecord (= 8.1.0) - activestorage (= 8.1.0) - activesupport (= 8.1.0) + actionpack (= 8.1.2) + activerecord (= 8.1.2) + activestorage (= 8.1.2) + activesupport (= 8.1.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.1.0) - activesupport (= 8.1.0) + actionview (8.1.2) + activesupport (= 8.1.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (8.1.0) - activesupport (= 8.1.0) + activejob (8.1.2) + activesupport (= 8.1.2) globalid (>= 0.3.6) - activemodel (8.1.0) - activesupport (= 8.1.0) - activerecord (8.1.0) - activemodel (= 8.1.0) - activesupport (= 8.1.0) + activemodel (8.1.2) + activesupport (= 8.1.2) + activerecord (8.1.2) + activemodel (= 8.1.2) + activesupport (= 8.1.2) timeout (>= 0.4.0) - activestorage (8.1.0) - actionpack (= 8.1.0) - activejob (= 8.1.0) - activerecord (= 8.1.0) - activesupport (= 8.1.0) + activestorage (8.1.2) + actionpack (= 8.1.2) + activejob (= 8.1.2) + activerecord (= 8.1.2) + activesupport (= 8.1.2) marcel (~> 1.0) - activesupport (8.1.0) + activesupport (8.1.2) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) @@ -75,66 +75,66 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) - async (2.34.0) + async (2.36.0) console (~> 1.29) fiber-annotation io-event (~> 1.11) metrics (~> 0.12) traces (~> 0.18) - async-container (0.27.7) + async-container (0.30.0) async (~> 2.22) - async-container-supervisor (0.8.0) + async-container-supervisor (0.9.3) async-service io-endpoint memory (~> 0.7) memory-leak (~> 0.5) process-metrics - async-http (0.92.1) + async-http (0.94.2) async (>= 2.10.2) async-pool (~> 0.11) io-endpoint (~> 0.14) io-stream (~> 0.6) metrics (~> 0.12) - protocol-http (~> 0.49) - protocol-http1 (~> 0.30) + protocol-http (~> 0.58) + protocol-http1 (~> 0.36) protocol-http2 (~> 0.22) protocol-url (~> 0.2) traces (~> 0.10) async-http-cache (0.4.6) async-http (~> 0.56) - async-pool (0.11.0) + async-pool (0.11.1) async (>= 2.0) - async-service (0.14.4) + async-service (0.19.1) async - async-container (~> 0.16) + async-container (~> 0.29) string-format (~> 0.2) bake (0.24.1) bigdecimal samovar (~> 2.1) base64 (0.3.0) - bigdecimal (3.3.1) + bigdecimal (4.0.1) builder (3.3.0) - concurrent-ruby (1.3.5) - connection_pool (2.5.4) - console (1.34.2) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + console (1.34.3) fiber-annotation fiber-local (~> 1.1) json crass (1.0.6) - date (3.4.1) + date (3.5.1) drb (2.2.3) - erb (5.1.3) + erb (6.0.2) erubi (1.13.1) - falcon (0.52.4) + falcon (0.54.2) async async-container (~> 0.20) async-container-supervisor (~> 0.6) async-http (~> 0.75) async-http-cache (~> 0.4) - async-service (~> 0.10) + async-service (~> 0.19) bundler localhost (~> 1.1) - openssl (~> 3.0) + openssl (>= 3.0) protocol-http (~> 0.31) protocol-rack (~> 0.7) samovar (~> 2.3) @@ -144,21 +144,22 @@ GEM fiber-storage (1.0.1) globalid (1.3.0) activesupport (>= 6.1) - i18n (1.14.7) + i18n (1.14.8) concurrent-ruby (~> 1.0) - io-console (0.8.1) - io-endpoint (0.15.2) - io-event (1.14.0) - io-stream (0.11.0) + io-console (0.8.2) + io-endpoint (0.17.2) + io-event (1.14.2) + io-stream (0.11.1) iodine (0.7.58) - irb (1.15.2) + irb (1.17.0) pp (>= 0.6.0) + prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.16.0) - localhost (1.6.0) + json (2.19.1) + localhost (1.7.0) logger (1.7.0) - loofah (2.24.1) + loofah (2.25.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.9.0) @@ -169,7 +170,7 @@ GEM net-smtp mapping (1.1.3) marcel (1.1.0) - memory (0.7.1) + memory (0.12.0) bake (~> 0.15) console msgpack @@ -177,9 +178,11 @@ GEM metrics (0.15.0) mini_mime (1.1.5) mini_portile2 (2.8.9) - minitest (5.26.0) + minitest (6.0.2) + drb (~> 2.0) + prism (~> 1.5) msgpack (1.8.0) - net-imap (0.5.12) + net-imap (0.6.2) date net-protocol net-pop (0.1.2) @@ -188,84 +191,87 @@ GEM timeout net-smtp (0.5.1) net-protocol - nio4r (2.7.4) - nokogiri (1.18.10) + nio4r (2.7.5) + nokogiri (1.19.1) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.18.10-x86_64-darwin) + nokogiri (1.19.1-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.10-x86_64-linux-gnu) + nokogiri (1.19.1-x86_64-linux-gnu) racc (~> 1.4) - openssl (3.3.2) - pg (1.5.9) + openssl (4.0.0) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) pitchfork (0.17.0) logger rack (>= 2.0) pp (0.6.3) prettyprint prettyprint (0.2.0) - process-metrics (0.6.0) + prism (1.9.0) + process-metrics (0.8.0) console (~> 1.8) json (~> 2) samovar (~> 2.1) protocol-hpack (1.5.1) - protocol-http (0.55.0) - protocol-http1 (0.35.2) - protocol-http (~> 0.22) - protocol-http2 (0.23.0) + protocol-http (0.59.0) + protocol-http1 (0.37.0) + protocol-http (~> 0.58) + protocol-http2 (0.24.0) protocol-hpack (~> 1.4) protocol-http (~> 0.47) - protocol-rack (0.16.0) + protocol-rack (0.21.1) io-stream (>= 0.10) - protocol-http (~> 0.43) + protocol-http (~> 0.58) rack (>= 1.0) protocol-url (0.4.0) - psych (5.2.6) + psych (5.3.1) date stringio - puma (7.1.0) + puma (7.2.0) nio4r (~> 2.0) racc (1.8.1) - rack (3.2.3) + rack (3.2.5) rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) rack-test (2.2.0) rack (>= 1.3) - rackup (2.2.1) + rackup (2.3.1) rack (>= 3) - rails (8.1.0) - actioncable (= 8.1.0) - actionmailbox (= 8.1.0) - actionmailer (= 8.1.0) - actionpack (= 8.1.0) - actiontext (= 8.1.0) - actionview (= 8.1.0) - activejob (= 8.1.0) - activemodel (= 8.1.0) - activerecord (= 8.1.0) - activestorage (= 8.1.0) - activesupport (= 8.1.0) + rails (8.1.2) + actioncable (= 8.1.2) + actionmailbox (= 8.1.2) + actionmailer (= 8.1.2) + actionpack (= 8.1.2) + actiontext (= 8.1.2) + actionview (= 8.1.2) + activejob (= 8.1.2) + activemodel (= 8.1.2) + activerecord (= 8.1.2) + activestorage (= 8.1.2) + activesupport (= 8.1.2) bundler (>= 1.15.0) - railties (= 8.1.0) + railties (= 8.1.2) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.2) - loofah (~> 2.21) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (8.1.0) - actionpack (= 8.1.0) - activesupport (= 8.1.0) + railties (8.1.2) + actionpack (= 8.1.2) + activesupport (= 8.1.2) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) tsort (>= 0.2) zeitwerk (~> 2.6) - rake (13.3.0) - rdoc (6.15.0) + rake (13.3.1) + rdoc (7.2.0) erb psych (>= 4.0.0) tsort @@ -273,30 +279,31 @@ GEM redis-client (>= 0.22.0) redis-client (0.24.0) connection_pool - reline (0.6.2) + reline (0.6.3) io-console (~> 0.5) samovar (2.4.1) console (~> 1.0) mapping (~> 1.0) securerandom (0.4.1) string-format (0.2.0) - stringio (3.1.7) - thor (1.4.0) - timeout (0.4.3) + stringio (3.2.0) + thor (1.5.0) + timeout (0.6.0) traces (0.18.2) - trilogy (2.8.1) + trilogy (2.10.0) + bigdecimal tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) tzinfo-data (1.2025.1) tzinfo (>= 1.0.0) - uri (1.0.4) + uri (1.1.1) useragent (0.16.11) websocket-driver (0.8.0) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.7.3) + zeitwerk (2.7.5) PLATFORMS ruby @@ -311,8 +318,8 @@ DEPENDENCIES puma (~> 7.1) rails (~> 8.1.0) redis (~> 5.0) - trilogy (~> 2.8.1) + trilogy (~> 2.10) tzinfo-data BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb b/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb index d314038144c..9201a74e424 100644 --- a/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb +++ b/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + module DateHeader extend ActiveSupport::Concern included do - if defined?(Agoo) || defined?(Falcon) || defined?(Puma) + if defined?(Falcon) || defined?(Puma) before_action :add_header end end diff --git a/frameworks/Ruby/rails/app/controllers/hello_world_controller.rb b/frameworks/Ruby/rails/app/controllers/hello_world_controller.rb index 526d850e94c..eb2d3f16ca2 100644 --- a/frameworks/Ruby/rails/app/controllers/hello_world_controller.rb +++ b/frameworks/Ruby/rails/app/controllers/hello_world_controller.rb @@ -14,7 +14,7 @@ def db def query results = ALL_IDS.sample(query_count).map do |id| - World.find(id) + World.find(id).attributes end render json: results diff --git a/frameworks/Ruby/rails/benchmark_config.json b/frameworks/Ruby/rails/benchmark_config.json index 5f86a525145..df99cca1cfe 100644 --- a/frameworks/Ruby/rails/benchmark_config.json +++ b/frameworks/Ruby/rails/benchmark_config.json @@ -22,7 +22,7 @@ "database_os": "Linux", "display_name": "rails [puma, postgres]", "notes": "", - "versus": "" + "versus": "rack" }, "mysql": { "db_url": "/db", @@ -43,7 +43,7 @@ "database_os": "Linux", "display_name": "rails [puma, mysql]", "notes": "", - "versus": "rack-puma-mri" + "versus": "" }, "falcon": { "db_url": "/db", @@ -66,7 +66,7 @@ "database_os": "Linux", "display_name": "rails [falcon]", "notes": "", - "versus": "rack-falcon-mri-sequel-raw" + "versus": "rack-falcon" }, "iodine": { "db_url": "/db", @@ -89,7 +89,7 @@ "database_os": "Linux", "display_name": "rails [iodine]", "notes": "", - "versus": "rack-iodine-mri-sequel-raw" + "versus": "rack-iodine" }, "pitchfork": { "db_url": "/db", @@ -112,7 +112,7 @@ "database_os": "Linux", "display_name": "rails [pitchfork]", "notes": "", - "versus": "rack-pitchfork-mri-sequel-raw" + "versus": "rack-pitchfork" } }] } diff --git a/frameworks/Ruby/rails/config/agoo.rb b/frameworks/Ruby/rails/config/agoo.rb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frameworks/Ruby/rails/config/pitchfork.rb b/frameworks/Ruby/rails/config/pitchfork.rb index e50470d2ed8..06468ebae42 100644 --- a/frameworks/Ruby/rails/config/pitchfork.rb +++ b/frameworks/Ruby/rails/config/pitchfork.rb @@ -1,9 +1,6 @@ # frozen_string_literal: true +require 'etc' -require_relative 'auto_tune' - -num_workers, = auto_tune - -worker_processes num_workers +worker_processes (Etc.nprocessors * 1.5).to_i listen "/tmp/.sock", :backlog => 4096 diff --git a/frameworks/Ruby/rails/config/routes.rb b/frameworks/Ruby/rails/config/routes.rb index 22c47dc8704..02c9d48195c 100644 --- a/frameworks/Ruby/rails/config/routes.rb +++ b/frameworks/Ruby/rails/config/routes.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - JsonApp = if defined?(Falcon) || defined?(Puma) || defined?(Agoo) + JsonApp = if defined?(Falcon) || defined?(Puma) ->(env) do [200, { @@ -9,7 +11,7 @@ 'Content-Type' => 'application/json', 'Date' => Time.now.httpdate, }, - [{ 'message' => 'Hello, World!' }.to_json]] + [JSON.generate({ 'message' => 'Hello, World!' })]] end else ->(env) do @@ -18,11 +20,11 @@ 'Server' => 'Rails', 'Content-Type' => 'application/json' }, - [{ 'message' => 'Hello, World!' }.to_json]] + [JSON.generate({ 'message' => 'Hello, World!' })]] end end - PlaintextApp = if defined?(Falcon) || defined?(Puma) || defined?(Agoo) + PlaintextApp = if defined?(Falcon) || defined?(Puma) ->(env) do [200, { diff --git a/frameworks/Ruby/rails/rails-falcon.dockerfile b/frameworks/Ruby/rails/rails-falcon.dockerfile index c92590a0f19..38475adb0dc 100644 --- a/frameworks/Ruby/rails/rails-falcon.dockerfile +++ b/frameworks/Ruby/rails/rails-falcon.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server diff --git a/frameworks/Ruby/rails/rails-iodine.dockerfile b/frameworks/Ruby/rails/rails-iodine.dockerfile index 90020e652fa..afe88dcbcbd 100644 --- a/frameworks/Ruby/rails/rails-iodine.dockerfile +++ b/frameworks/Ruby/rails/rails-iodine.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server @@ -24,4 +24,4 @@ ENV RAILS_ENV=production_postgresql ENV PORT=8080 ENV REDIS_URL=redis://localhost:6379/0 CMD service redis-server start && \ - bundle exec iodine -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) + bundle exec iodine -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/rails/rails-mysql.dockerfile b/frameworks/Ruby/rails/rails-mysql.dockerfile index 998294d1ec6..3e5f938d0c6 100644 --- a/frameworks/Ruby/rails/rails-mysql.dockerfile +++ b/frameworks/Ruby/rails/rails-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server @@ -6,6 +6,7 @@ EXPOSE 8080 WORKDIR /rails # ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -20,10 +21,10 @@ RUN bundle install --jobs=8 COPY . /rails/ -ENV WEB_CONCURRENCY=auto ENV RAILS_MAX_THREADS=5 ENV RAILS_ENV=production_mysql ENV PORT=8080 ENV REDIS_URL=redis://localhost:6379/0 -CMD service redis-server start && \ +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + service redis-server start && \ bin/rails server diff --git a/frameworks/Ruby/rails/rails-pitchfork.dockerfile b/frameworks/Ruby/rails/rails-pitchfork.dockerfile index 53f8c66b4cc..0220e49c841 100644 --- a/frameworks/Ruby/rails/rails-pitchfork.dockerfile +++ b/frameworks/Ruby/rails/rails-pitchfork.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server @@ -6,6 +6,7 @@ EXPOSE 8080 WORKDIR /rails # ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index 2e901b62062..41b2b4df1a7 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server @@ -6,6 +6,7 @@ EXPOSE 8080 WORKDIR /rails # ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -20,10 +21,10 @@ RUN bundle install --jobs=8 COPY . /rails/ -ENV WEB_CONCURRENCY=auto ENV RAILS_MAX_THREADS=5 ENV RAILS_ENV=production_postgresql ENV PORT=8080 ENV REDIS_URL=redis://localhost:6379/0 -CMD service redis-server start && \ +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + service redis-server start && \ bin/rails server diff --git a/frameworks/Ruby/roda-sequel/Gemfile b/frameworks/Ruby/roda-sequel/Gemfile index c78013dc75d..fd63c58fcc0 100644 --- a/frameworks/Ruby/roda-sequel/Gemfile +++ b/frameworks/Ruby/roda-sequel/Gemfile @@ -1,7 +1,7 @@ source "https://rubygems.org" gem "erubi", "~> 1.12" -gem "json", "~> 2.8" +gem "json" gem "sequel", "~> 5.67" gem "roda", "~> 3.66" gem "tilt", "~> 2.1", require: "tilt/erb" @@ -9,18 +9,14 @@ gem "cgi" # Make sure the h plugin uses the faster CGI.escape_html gem "concurrent-ruby" group :mysql, optional: true do - gem 'trilogy', '~> 2.9', platforms: [:ruby, :windows] + gem "trilogy", "~> 2.10" end group :postgresql, optional: true do - gem "pg", "~> 1.4", platforms: %i[ruby windows] - gem "sequel_pg", "~> 1.17", platforms: :ruby, require: false + gem "pg", "~> 1.4" + gem "sequel_pg", "~> 1.17", require: "sequel" end group :iodine, optional: true do gem "iodine", "~> 0.7", require: false end - -group :puma, optional: true do - gem "puma", "~> 7.1", require: false -end diff --git a/frameworks/Ruby/roda-sequel/Gemfile.lock b/frameworks/Ruby/roda-sequel/Gemfile.lock index 37c5ce6a06e..5f4ad2b9a5e 100644 --- a/frameworks/Ruby/roda-sequel/Gemfile.lock +++ b/frameworks/Ruby/roda-sequel/Gemfile.lock @@ -1,28 +1,26 @@ GEM remote: https://rubygems.org/ specs: - bigdecimal (3.1.9) + bigdecimal (4.0.1) cgi (0.5.0) concurrent-ruby (1.3.5) erubi (1.13.1) iodine (0.7.58) - json (2.16.0) - nio4r (2.7.4) - pg (1.6.2) - pg (1.6.2-x86_64-darwin) - pg (1.6.2-x86_64-linux) - puma (7.1.0) - nio4r (~> 2.0) - rack (3.2.3) - roda (3.90.0) + json (2.18.0) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) + rack (3.2.4) + roda (3.99.0) rack - sequel (5.90.0) + sequel (5.100.0) bigdecimal - sequel_pg (1.17.1) + sequel_pg (1.18.2) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) tilt (2.6.0) - trilogy (2.9.0) + trilogy (2.10.0) + bigdecimal PLATFORMS ruby @@ -34,14 +32,13 @@ DEPENDENCIES concurrent-ruby erubi (~> 1.12) iodine (~> 0.7) - json (~> 2.8) + json pg (~> 1.4) - puma (~> 7.1) roda (~> 3.66) sequel (~> 5.67) sequel_pg (~> 1.17) tilt (~> 2.1) - trilogy (~> 2.9) + trilogy (~> 2.10) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/roda-sequel/benchmark_config.json b/frameworks/Ruby/roda-sequel/benchmark_config.json index c028cc7008c..39cee77c2fa 100644 --- a/frameworks/Ruby/roda-sequel/benchmark_config.json +++ b/frameworks/Ruby/roda-sequel/benchmark_config.json @@ -7,7 +7,6 @@ "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", @@ -17,11 +16,11 @@ "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Puma", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel [puma, mysql]", - "versus": "rack-sequel-puma-mri", + "display_name": "roda-sequel [mysql]", + "versus": "rack-sequel-iodine", "notes": "" }, "postgres": { @@ -37,33 +36,11 @@ "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Puma", - "os": "Linux", - "database_os": "Linux", - "display_name": "roda-sequel [puma, postgres]", - "versus": "rack-sequel-postgres-puma-mri", - "notes": "" - }, - "postgres-iodine-mri": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roda-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel [iodine, postgres]", - "versus": "rack-sequel-postgres-iodine-mri", + "display_name": "roda-sequel [postgres]", + "versus": "rack-sequel-iodine-postgres", "notes": "" } } diff --git a/frameworks/Ruby/roda-sequel/boot.rb b/frameworks/Ruby/roda-sequel/boot.rb deleted file mode 100644 index 6d2d2e44e9f..00000000000 --- a/frameworks/Ruby/roda-sequel/boot.rb +++ /dev/null @@ -1,83 +0,0 @@ -# frozen_string_literal: true -require "bundler/setup" -require "time" -MAX_PK = 10_000 -QUERY_RANGE = (1..MAX_PK).freeze -ALL_IDS = QUERY_RANGE.to_a -QUERIES_MIN = 1 -QUERIES_MAX = 500 -SEQUEL_NO_ASSOCIATIONS = true - -SERVER_STRING = "roda" - -Bundler.require(:default) # Load core modules - -CONTENT_TYPE = 'Content-Type' -JSON_TYPE = 'application/json' -HTML_TYPE = 'text/html; charset=utf-8' -PLAINTEXT_TYPE = 'text/plain' -DATE_HEADER = 'Date' -SERVER_HEADER = 'Server' - -def connect(dbtype) - Bundler.require(dbtype) # Load database-specific modules - - opts = {} - - if dbtype == :mysql - adapter = 'trilogy' - opts[:ssl] = true - opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY - opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 - else - adapter = 'postgresql' - end - - # Determine threading/thread pool size and timeout - if defined?(Puma) - opts[:max_connections] = ENV.fetch('MAX_THREADS') - opts[:pool_timeout] = 10 - else - opts[:max_connections] = 512 - end - - Sequel.connect "%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}" % - { - adapter: adapter, - host: "tfb-database", - database: "hello_world", - user: "benchmarkdbuser", - password: "benchmarkdbpass" - }, - opts -end - -DB = connect ENV.fetch("DBTYPE").to_sym - -# Define ORM models -class World < Sequel.Model(:World) - def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql - - def self.batch_update(worlds) - if DB.database_type == :mysql - worlds.map(&:save_changes) - else - ids = [] - sql = String.new("UPDATE world SET randomnumber = CASE id ") - worlds.each do |world| - sql << "when #{world.id} then #{world.randomnumber} " - ids << world.id - end - sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" - DB.run(sql) - end - end -end - -class Fortune < Sequel.Model(:Fortune) - # Allow setting id to zero (0) per benchmark requirements - unrestrict_primary_key -end - -[World, Fortune].each(&:freeze) -DB.freeze diff --git a/frameworks/Ruby/roda-sequel/config.ru b/frameworks/Ruby/roda-sequel/config.ru index 58f0ca7496a..bc64c3d5fbc 100644 --- a/frameworks/Ruby/roda-sequel/config.ru +++ b/frameworks/Ruby/roda-sequel/config.ru @@ -1,3 +1,4 @@ -require_relative 'boot' +# frozen_string_literal: true require_relative 'hello_world' + run HelloWorld.freeze.app diff --git a/frameworks/Ruby/roda-sequel/config/auto_tune.rb b/frameworks/Ruby/roda-sequel/config/auto_tune.rb deleted file mode 100644 index 495956c0700..00000000000 --- a/frameworks/Ruby/roda-sequel/config/auto_tune.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - fail "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - (Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $0 == __FILE__ diff --git a/frameworks/Ruby/roda-sequel/db.rb b/frameworks/Ruby/roda-sequel/db.rb new file mode 100644 index 00000000000..20b7698f0c7 --- /dev/null +++ b/frameworks/Ruby/roda-sequel/db.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +SEQUEL_NO_ASSOCIATIONS = true + +def connect(dbtype) + Bundler.require(dbtype) # Load database-specific modules + + opts = {} + + if dbtype == :mysql + adapter = 'trilogy' + opts[:ssl] = true + opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY + opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 + else + adapter = 'postgresql' + end + + # Determine threading/thread pool size and timeout + if defined?(Puma) + opts[:max_connections] = ENV.fetch('MAX_THREADS') + opts[:pool_timeout] = 10 + else + opts[:max_connections] = 512 + end + + Sequel.connect "%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}" % + { + adapter: adapter, + host: "tfb-database", + database: "hello_world", + user: "benchmarkdbuser", + password: "benchmarkdbpass" + }, + opts +end + +DB = connect ENV.fetch("DBTYPE").to_sym + +# Define ORM models +class World < Sequel.Model(:World) + def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql + + def self.batch_update(worlds) + ids = [] + sql = String.new("UPDATE world SET randomnumber = CASE id ") + worlds.each do |world| + sql << "when #{world.id} then #{world.randomnumber} " + ids << world.id + end + sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" + DB.run(sql) + end +end + +class Fortune < Sequel.Model(:Fortune) + # Allow setting id to zero (0) per benchmark requirements + unrestrict_primary_key +end + +[World, Fortune].each(&:freeze) +DB.freeze diff --git a/frameworks/Ruby/roda-sequel/hello_world.rb b/frameworks/Ruby/roda-sequel/hello_world.rb index a3da529b8d2..42bf22c3afc 100644 --- a/frameworks/Ruby/roda-sequel/hello_world.rb +++ b/frameworks/Ruby/roda-sequel/hello_world.rb @@ -1,9 +1,29 @@ # frozen_string_literal: true +require 'bundler/setup' +Bundler.require(:default) # Load core modules + +require_relative 'db' +require 'time' # Our Rack application to be executed by rackup class HelloWorld < Roda + MAX_PK = 10_000 + QUERY_RANGE = (1..MAX_PK).freeze + ALL_IDS = QUERY_RANGE.to_a + QUERIES_MIN = 1 + QUERIES_MAX = 500 + + CONTENT_TYPE = 'Content-Type' + JSON_TYPE = 'application/json' + HTML_TYPE = 'text/html; charset=utf-8' + PLAINTEXT_TYPE = 'text/plain' + DATE_HEADER = 'Date' + SERVER_HEADER = 'Server' + SERVER_STRING = 'roda' + plugin :hooks plugin :render, escape: true, layout_opts: { cache_key: "default_layout" } + plugin :default_headers, SERVER_HEADER => SERVER_STRING def bounded_queries queries = request.params["queries"].to_i @@ -15,30 +35,19 @@ def rand1 rand(MAX_PK) + 1 end - if defined?(Puma) - def set_default_headers(response) - response[DATE_HEADER] = Time.now.httpdate - response[SERVER_HEADER] = SERVER_STRING - end - else - def set_default_headers(response) - response[SERVER_HEADER] = SERVER_STRING - end - end - route do |r| - set_default_headers(response) + response[DATE_HEADER] = Time.now.httpdate if defined?(Puma) # Test type 1: JSON serialization r.is "json" do response[CONTENT_TYPE] = JSON_TYPE - { message: "Hello, World!" }.to_json + JSON.generate({ message: "Hello, World!" }) end # Test type 2: Single database query r.is "db" do response[CONTENT_TYPE] = JSON_TYPE - World.with_pk(rand1).values.to_json + JSON.generate(World.with_pk(rand1).values) end # Test type 3: Multiple database queries @@ -51,17 +60,19 @@ def set_default_headers(response) World.with_pk(id).values end end - worlds.to_json + JSON.generate(worlds) end # Test type 4: Fortunes r.is "fortunes" do response[CONTENT_TYPE] = HTML_TYPE @fortunes = Fortune.all - @fortunes << Fortune.new( - id: 0, - message: "Additional fortune added at request time." - ) + + fortune = Fortune.new + fortune.id = 0 + fortune.message = "Additional fortune added at request time." + @fortunes << fortune + @fortunes.sort_by!(&:message) view :fortunes end @@ -82,7 +93,7 @@ def set_default_headers(response) end World.batch_update(worlds) end - worlds.map!(&:values).to_json + JSON.generate(worlds.map!(&:values)) end # Test type 6: Plaintext diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile deleted file mode 100644 index db7fbc995f1..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ruby:4.0-rc - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV RUBY_YJIT_ENABLE=1 - -# Use Jemalloc -RUN apt-get update && \ - apt-get install -y --no-install-recommends libjemalloc2 -ENV LD_PRELOAD=libjemalloc.so.2 - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle config set with 'postgresql iodine' -RUN bundle install --jobs=8 - -ENV RACK_ENV=production -ENV DBTYPE=postgresql - -EXPOSE 8080 - -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile index f64942e8994..6710c45a8fa 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ADD ./ /roda-sequel WORKDIR /roda-sequel @@ -11,15 +11,12 @@ RUN apt-get update && \ ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle config set with 'postgresql puma' +RUN bundle config set with 'postgresql iodine' RUN bundle install --jobs=8 ENV RACK_ENV=production ENV DBTYPE=postgresql -ENV MAX_THREADS=5 -ENV WEB_CONCURRENCY=auto - EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile index d72f87057db..a34011a0a45 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ADD ./ /roda-sequel WORKDIR /roda-sequel @@ -11,15 +11,12 @@ RUN apt-get update && \ ENV LD_PRELOAD=libjemalloc.so.2 ENV BUNDLE_FORCE_RUBY_PLATFORM=true -RUN bundle config set with 'mysql puma' +RUN bundle config set with 'mysql iodine' RUN bundle install --jobs=8 ENV RACK_ENV=production ENV DBTYPE=mysql -ENV WEB_CONCURRENCY=auto -ENV MAX_THREADS=5 - EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/sinatra-sequel/.gitignore b/frameworks/Ruby/sinatra-sequel/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile b/frameworks/Ruby/sinatra-sequel/Gemfile index 6a685b432a6..598429a337d 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile +++ b/frameworks/Ruby/sinatra-sequel/Gemfile @@ -2,19 +2,19 @@ source 'https://rubygems.org' gem 'json', '~> 2.8' gem 'sequel', '~> 5.0' -gem 'sinatra', '~> 4.0', :require=>'sinatra/base' +gem 'sinatra', '~> 4.0', require: 'sinatra/base' group :mysql, optional: true do - gem 'trilogy', '~> 2.9', platforms: [:ruby, :windows] + gem 'trilogy', '~> 2.10' end group :postgresql, optional: true do - gem 'pg', '~> 1.5', :platforms=>[:ruby, :windows] - gem 'sequel_pg', '~> 1.6', :platforms=>:ruby, :require=>false + gem 'pg', '~> 1.5' + gem 'sequel_pg', '~> 1.17', require: 'sequel' end group :iodine, optional: true do - gem 'iodine', '~> 0.7', platforms: [:ruby, :windows], require: false + gem 'iodine', '~> 0.7', require: false end group :puma, optional: true do diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile.lock b/frameworks/Ruby/sinatra-sequel/Gemfile.lock index 5d1d43e6228..5d1ceaf5d9c 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile.lock +++ b/frameworks/Ruby/sinatra-sequel/Gemfile.lock @@ -2,18 +2,18 @@ GEM remote: https://rubygems.org/ specs: base64 (0.3.0) - bigdecimal (3.3.1) + bigdecimal (4.0.1) concurrent-ruby (1.3.5) iodine (0.7.58) - json (2.16.0) + json (2.18.0) logger (1.7.0) mustermann (3.0.4) ruby2_keywords (~> 0.0.1) - nio4r (2.7.4) - pg (1.6.2) - pg (1.6.2-x86_64-darwin) - pg (1.6.2-x86_64-linux) - puma (7.1.0) + nio4r (2.7.5) + pg (1.6.3) + pg (1.6.3-x86_64-darwin) + pg (1.6.3-x86_64-linux) + puma (7.2.0) nio4r (~> 2.0) rack (3.2.4) rack-protection (4.2.1) @@ -24,9 +24,9 @@ GEM base64 (>= 0.1.0) rack (>= 3.0.0) ruby2_keywords (0.0.5) - sequel (5.97.0) + sequel (5.100.0) bigdecimal - sequel_pg (1.17.2) + sequel_pg (1.18.2) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) sinatra (4.2.1) @@ -37,7 +37,8 @@ GEM rack-session (>= 2.0.0, < 3) tilt (~> 2.0) tilt (2.6.1) - trilogy (2.9.0) + trilogy (2.10.0) + bigdecimal PLATFORMS ruby @@ -51,9 +52,9 @@ DEPENDENCIES pg (~> 1.5) puma (~> 7.1) sequel (~> 5.0) - sequel_pg (~> 1.6) + sequel_pg (~> 1.17) sinatra (~> 4.0) - trilogy (~> 2.9) + trilogy (~> 2.10) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/sinatra-sequel/benchmark_config.json b/frameworks/Ruby/sinatra-sequel/benchmark_config.json index 008e63a8148..917023e3416 100644 --- a/frameworks/Ruby/sinatra-sequel/benchmark_config.json +++ b/frameworks/Ruby/sinatra-sequel/benchmark_config.json @@ -6,7 +6,6 @@ "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -19,7 +18,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "sinatra-sequel [puma, mysql]", - "versus": "rack-sequel-puma-mri", + "versus": "rack-sequel", "notes": "" }, "postgres": { @@ -39,7 +38,26 @@ "os": "Linux", "database_os": "Linux", "display_name": "sinatra-sequel [puma, postgres]", - "versus": "rack-sequel-postgres-puma-mri", + "versus": "rack-sequel-postgres", + "notes": "" + }, + "iodine": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "sinatra", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "sinatra-sequel [iodine, mysql]", + "versus": "rack-sequel-iodine", "notes": "" }, "postgres-iodine-mri": { @@ -59,7 +77,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "sinatra-sequel [iodine, postgres]", - "versus": "rack-sequel-postgres-iodine-mri", + "versus": "rack-sequel-iodine-postgres", "notes": "" } } diff --git a/frameworks/Ruby/sinatra-sequel/boot.rb b/frameworks/Ruby/sinatra-sequel/boot.rb deleted file mode 100644 index 58cdb0c25cb..00000000000 --- a/frameworks/Ruby/sinatra-sequel/boot.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true -require 'bundler/setup' -require 'time' - -MAX_PK = 10_000 -ID_RANGE = (1..MAX_PK).freeze -ALL_IDS = ID_RANGE.to_a -QUERIES_MIN = 1 -QUERIES_MAX = 500 -SEQUEL_NO_ASSOCIATIONS = true -SERVER_STRING = "Sinatra" - -Bundler.require(:default) # Load core modules - -def connect(dbtype) - Bundler.require(dbtype) # Load database-specific modules - - opts = {} - - if dbtype == :mysql - adapter = 'trilogy' - opts[:ssl] = true - opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY - opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 - else - adapter = 'postgresql' - end - - # Determine threading/thread pool size and timeout - if defined?(Puma) - opts[:max_connections] = ENV.fetch('MAX_THREADS') - opts[:pool_timeout] = 10 - else - opts[:max_connections] = 512 - end - - Sequel.connect \ - '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { - adapter: adapter, - host: 'tfb-database', - database: 'hello_world', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass' - }, opts -end - -DB = connect ENV.fetch('DBTYPE').to_sym - -# Define ORM models -class World < Sequel::Model(:World) - def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql - - def self.batch_update(worlds) - if DB.database_type == :mysql - worlds.map(&:save_changes) - else - ids = [] - sql = String.new("UPDATE world SET randomnumber = CASE id ") - worlds.each do |world| - sql << "when #{world.id} then #{world.randomnumber} " - ids << world.id - end - sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" - DB.run(sql) - end - end -end - -class Fortune < Sequel::Model(:Fortune) - # Allow setting id to zero (0) per benchmark requirements - unrestrict_primary_key -end - -[World, Fortune].each(&:freeze) -DB.freeze diff --git a/frameworks/Ruby/sinatra-sequel/config.ru b/frameworks/Ruby/sinatra-sequel/config.ru index a8b9b9cdc91..f615b59a80e 100644 --- a/frameworks/Ruby/sinatra-sequel/config.ru +++ b/frameworks/Ruby/sinatra-sequel/config.ru @@ -1,3 +1,4 @@ -require_relative 'boot' +# frozen_string_literal: true require_relative 'hello_world' + run HelloWorld.new diff --git a/frameworks/Ruby/sinatra-sequel/config/auto_tune.rb b/frameworks/Ruby/sinatra-sequel/config/auto_tune.rb deleted file mode 100644 index 495956c0700..00000000000 --- a/frameworks/Ruby/sinatra-sequel/config/auto_tune.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - fail "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - (Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $0 == __FILE__ diff --git a/frameworks/Ruby/sinatra-sequel/db.rb b/frameworks/Ruby/sinatra-sequel/db.rb new file mode 100644 index 00000000000..9e3346c5758 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/db.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +SEQUEL_NO_ASSOCIATIONS = true + +def connect(dbtype) + Bundler.require(dbtype) # Load database-specific modules + + opts = {} + + if dbtype == :mysql + adapter = 'trilogy' + opts[:ssl] = true + opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY + opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 + else + adapter = 'postgresql' + end + + # Determine threading/thread pool size and timeout + if defined?(Puma) + opts[:max_connections] = ENV.fetch('MAX_THREADS') + opts[:pool_timeout] = 10 + else + opts[:max_connections] = 512 + end + + Sequel.connect \ + '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { + adapter: adapter, + host: 'tfb-database', + database: 'hello_world', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' + }, opts +end + +DB = connect ENV.fetch('DBTYPE').to_sym + +# Define ORM models +class World < Sequel::Model(:World) + def_column_alias(:randomnumber, :randomNumber) if DB.database_type == :mysql + + def self.batch_update(worlds) + if DB.database_type == :mysql + worlds.map(&:save_changes) + else + ids = [] + sql = String.new("UPDATE world SET randomnumber = CASE id ") + worlds.each do |world| + sql << "when #{world.id} then #{world.randomnumber} " + ids << world.id + end + sql << "ELSE randomnumber END WHERE id IN ( #{ids.join(',')})" + DB.run(sql) + end + end +end + +class Fortune < Sequel::Model(:Fortune) + # Allow setting id to zero (0) per benchmark requirements + unrestrict_primary_key +end + +[World, Fortune].each(&:freeze) +DB.freeze diff --git a/frameworks/Ruby/sinatra-sequel/hello_world.rb b/frameworks/Ruby/sinatra-sequel/hello_world.rb index f4410cd140c..3f08ab904a6 100644 --- a/frameworks/Ruby/sinatra-sequel/hello_world.rb +++ b/frameworks/Ruby/sinatra-sequel/hello_world.rb @@ -1,7 +1,22 @@ # frozen_string_literal: true +require 'bundler/setup' +Bundler.require(:default) # Load core modules + +require_relative 'db' +require 'time' # Our Rack application to be executed by rackup class HelloWorld < Sinatra::Base + MAX_PK = 10_000 + ID_RANGE = (1..MAX_PK).freeze + ALL_IDS = ID_RANGE.to_a + QUERIES_MIN = 1 + QUERIES_MAX = 500 + + DATE_HEADER = 'Date' + SERVER_HEADER = 'Server' + SERVER_STRING = 'Sinatra' + configure do # Static file serving is ostensibly disabled in modular mode but Sinatra # still calls an expensive Proc on every request... @@ -15,41 +30,22 @@ class HelloWorld < Sinatra::Base # Only add the charset parameter to specific content types per the requirements set :add_charset, [mime_type(:html)] - end - helpers do - def bounded_queries - queries = params[:queries].to_i - queries.clamp(QUERIES_MIN, QUERIES_MAX) - end - - def json(data) - content_type :json - data.to_json - end + # Disable logging middleware + set :logging, nil - # Return a random number between 1 and MAX_PK - def rand1 - rand(MAX_PK).succ - end + # Set root once instead executing the proc on every request + set :root, File.expand_path(__dir__) end - after do - response['Date'] = Time.now.httpdate - end if defined?(Falcon) || defined?(Puma) - - after do - response['Server'] = SERVER_STRING - end if SERVER_STRING - # Test type 1: JSON serialization get '/json' do - json :message=>'Hello, World!' + render_json message: 'Hello, World!' end # Test type 2: Single database query get '/db' do - json World.with_pk(rand1).values + render_json World.with_pk(rand1).values end # Test type 3: Multiple database queries @@ -62,19 +58,21 @@ def rand1 end end - json worlds.map!(&:values) + render_json worlds.map!(&:values) end # Test type 4: Fortunes get '/fortunes' do @fortunes = Fortune.all - @fortunes << Fortune.new( - :id=>0, - :message=>'Additional fortune added at request time.' - ) + + fortune = Fortune.new + fortune.id = 0 + fortune.message = "Additional fortune added at request time." + @fortunes << fortune + @fortunes.sort_by!(&:message) - erb :fortunes, :layout=>true + render_html :fortunes end # Test type 5: Database updates @@ -93,12 +91,51 @@ def rand1 World.batch_update(worlds) end - json worlds.map!(&:values) + render_json worlds.map!(&:values) end # Test type 6: Plaintext get '/plaintext' do + render_text 'Hello, World!' + end + + private + + def render_json(data) + add_headers + content_type :json + JSON.generate(data) + end + + def render_html(template) + add_headers + render :erb, template, layout: true + end + + def render_text(content) + add_headers content_type :text - 'Hello, World!' + content + end + + def bounded_queries + queries = params[:queries].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end + + # Return a random number between 1 and MAX_PK + def rand1 + rand(MAX_PK).succ + end + + if defined?(Puma) + def add_headers + response[SERVER_HEADER] = SERVER_STRING + response[DATE_HEADER] = Time.now.httpdate + end + else + def add_headers + response[SERVER_HEADER] = SERVER_STRING + end end end diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-iodine.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-iodine.dockerfile new file mode 100644 index 00000000000..d54aee6e577 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-iodine.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:4.0 + +ENV RUBY_YJIT_ENABLE=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +ADD ./ /sinatra-sequel +WORKDIR /sinatra-sequel + +ENV BUNDLE_WITH=mysql:iodine +RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile + +ENV APP_ENV=production +ENV DBTYPE=mysql + +EXPOSE 8080 + +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile index 98e42167f64..ca4f912450b 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 @@ -18,4 +18,4 @@ ENV DBTYPE=postgresql EXPOSE 8080 -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile index 7cfbf8d9cb6..4d2cee9138a 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile @@ -1,6 +1,7 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -16,9 +17,10 @@ RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile ENV APP_ENV=production ENV DBTYPE=postgresql -ENV WEB_CONCURRENCY=auto +ENV MIN_THREADS=5 ENV MAX_THREADS=5 EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile index bc8a7a8b871..ff865220602 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile @@ -1,6 +1,7 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -16,9 +17,10 @@ RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile ENV APP_ENV=production ENV DBTYPE=mysql -ENV WEB_CONCURRENCY=auto +ENV MIN_THREADS=5 ENV MAX_THREADS=5 EXPOSE 8080 -CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/.gitignore b/frameworks/Ruby/sinatra/.gitignore new file mode 100644 index 00000000000..a9a5aecf429 --- /dev/null +++ b/frameworks/Ruby/sinatra/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/frameworks/Ruby/sinatra/Gemfile b/frameworks/Ruby/sinatra/Gemfile index c02e8ff075b..1abdbccf1d3 100644 --- a/frameworks/Ruby/sinatra/Gemfile +++ b/frameworks/Ruby/sinatra/Gemfile @@ -1,19 +1,19 @@ source 'https://rubygems.org' gem 'activerecord', '~> 8.1.0', require: 'active_record' -gem 'json', '~> 2.8' +gem 'json' gem 'sinatra', '~> 4.2', require: 'sinatra/base' group :mysql, optional: true do - gem 'trilogy', '~> 2.9.0', platforms: [:ruby, :windows] + gem 'trilogy', '~> 2.10' end group :postgresql, optional: true do - gem 'pg', '~> 1.5', platforms: [:ruby, :windows] + gem 'pg', '~> 1.5' end group :iodine, optional: true do - gem 'iodine', '~> 0.7', platforms: [:ruby, :windows], require: false + gem 'iodine', '~> 0.7', require: false end group :puma, optional: true do diff --git a/frameworks/Ruby/sinatra/Gemfile.lock b/frameworks/Ruby/sinatra/Gemfile.lock index c4b7de85016..da06abf54a3 100644 --- a/frameworks/Ruby/sinatra/Gemfile.lock +++ b/frameworks/Ruby/sinatra/Gemfile.lock @@ -23,23 +23,23 @@ GEM base64 (0.3.0) bigdecimal (3.2.2) concurrent-ruby (1.3.5) - connection_pool (2.5.3) + connection_pool (3.0.2) drb (2.2.3) i18n (1.14.7) concurrent-ruby (~> 1.0) iodine (0.7.58) - json (2.16.0) + json (2.18.0) logger (1.7.0) minitest (5.25.5) mustermann (3.0.4) ruby2_keywords (~> 0.0.1) - nio4r (2.7.4) + nio4r (2.7.5) pg (1.6.2) pg (1.6.2-x86_64-darwin) pg (1.6.2-x86_64-linux) - puma (7.1.0) + puma (7.2.0) nio4r (~> 2.0) - rack (3.2.3) + rack (3.2.5) rack-protection (4.2.0) base64 (>= 0.1.0) logger (>= 1.6.0) @@ -58,10 +58,11 @@ GEM tilt (~> 2.0) tilt (2.6.1) timeout (0.4.3) - trilogy (2.9.0) + trilogy (2.10.0) + bigdecimal tzinfo (2.0.6) concurrent-ruby (~> 1.0) - uri (1.0.3) + uri (1.0.4) PLATFORMS ruby @@ -71,11 +72,11 @@ PLATFORMS DEPENDENCIES activerecord (~> 8.1.0) iodine (~> 0.7) - json (~> 2.8) + json pg (~> 1.5) puma (~> 7.1) sinatra (~> 4.2) - trilogy (~> 2.9.0) + trilogy (~> 2.10) BUNDLED WITH - 2.7.0 + 4.0.3 diff --git a/frameworks/Ruby/sinatra/benchmark_config.json b/frameworks/Ruby/sinatra/benchmark_config.json index 7bdbb62e853..9702473b2a7 100644 --- a/frameworks/Ruby/sinatra/benchmark_config.json +++ b/frameworks/Ruby/sinatra/benchmark_config.json @@ -7,7 +7,6 @@ "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", @@ -21,7 +20,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "sinatra [puma, mysql]", - "versus": "rack-puma-mri", + "versus": "", "notes": "" }, "postgres": { @@ -41,19 +40,38 @@ "os": "Linux", "database_os": "Linux", "display_name": "sinatra [puma, postgres]", - "versus": "rack-postgres-puma-mri", + "versus": "rack", "notes": "" }, - "postgres-iodine-mri": { + "iodine": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Micro", + "database": "MySQL", + "framework": "sinatra", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "sinatra [iodine, mysql]", + "versus": "", + "notes": "" + }, + "postgres-iodine-mri": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", "database": "Postgres", "framework": "sinatra", "language": "Ruby", @@ -63,7 +81,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "sinatra [iodine, postgres]", - "versus": "rack-postgres-iodine-mri", + "versus": "rack-iodine", "notes": "" } } diff --git a/frameworks/Ruby/sinatra/boot.rb b/frameworks/Ruby/sinatra/boot.rb deleted file mode 100644 index 33843258016..00000000000 --- a/frameworks/Ruby/sinatra/boot.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true -require 'bundler/setup' -require 'time' - -MAX_PK = 10_000 -ID_RANGE = (1..MAX_PK).freeze -ALL_IDS = ID_RANGE.to_a -QUERIES_MIN = 1 -QUERIES_MAX = 500 -SERVER_STRING = "Sinatra" - -Bundler.require(:default) # Load core modules - -def connect(dbtype) - Bundler.require(dbtype) # Load database-specific modules - - opts = { - username: 'benchmarkdbuser', - password: 'benchmarkdbpass', - host: 'tfb-database', - database: 'hello_world' - } - - if dbtype == :mysql - opts[:adapter] = 'trilogy' - opts[:ssl] = true - opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY - opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 - else - opts[:adapter] = 'postgresql' - end - - # Determine threading/thread pool size and timeout - if defined?(Puma) - opts[:pool] = ENV.fetch('MAX_THREADS') - opts[:checkout_timeout] = 10 - else - opts[:pool] = 512 - end - - ActiveRecord::Base.establish_connection(opts) -end - -connect ENV.fetch('DBTYPE').to_sym - -# Define ORM models -class World < ActiveRecord::Base - self.table_name = name - - alias_attribute(:randomNumber, :randomnumber) \ - if connection.adapter_name.downcase.start_with?('postgres') - - if connection.adapter_name.downcase.start_with?('trilogy') - def self.upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) - # On MySQL Batch updates verification isn't supported yet by TechEmpower. - # https://github.com/TechEmpower/FrameworkBenchmarks/issues/5983 - attributes.each do |attrs| - where(id: attrs[:id]).update_all(randomNumber: attrs[:randomNumber]) - end - end - end -end - -class Fortune < ActiveRecord::Base - self.table_name = name -end - -ActiveRecord::Base.connection_handler.clear_active_connections! diff --git a/frameworks/Ruby/sinatra/config.ru b/frameworks/Ruby/sinatra/config.ru index a8b9b9cdc91..f615b59a80e 100644 --- a/frameworks/Ruby/sinatra/config.ru +++ b/frameworks/Ruby/sinatra/config.ru @@ -1,3 +1,4 @@ -require_relative 'boot' +# frozen_string_literal: true require_relative 'hello_world' + run HelloWorld.new diff --git a/frameworks/Ruby/sinatra/config/auto_tune.rb b/frameworks/Ruby/sinatra/config/auto_tune.rb deleted file mode 100644 index 81bdabf7619..00000000000 --- a/frameworks/Ruby/sinatra/config/auto_tune.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby -# Instantiate about one process per X MiB of available memory, scaling up to as -# close to MAX_THREADS as possible while observing an upper bound based on the -# number of virtual/logical CPUs. If there are fewer processes than -# MAX_THREADS, add threads per process to reach MAX_THREADS. -require 'etc' - -KB_PER_WORKER = 96 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k) -MIN_WORKERS = 2 -MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical -MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) - -def meminfo(arg) - File.open('/proc/meminfo') do |f| - f.each_line do |line| - key, value = line.split(/:\s+/) - return value.split(/\s+/).first.to_i if key == arg - end - end - - fail "Unable to find `#{arg}' in /proc/meminfo!" -end - -def auto_tune - avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024 - - workers = [ - [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max, - (Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil - ].min - - threads_per_worker = [ - workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY, - MIN_THREADS_PER_WORKER - ].max - - [workers, threads_per_worker] -end - -p auto_tune if $0 == __FILE__ diff --git a/frameworks/Ruby/sinatra/config/puma.rb b/frameworks/Ruby/sinatra/config/puma.rb new file mode 100644 index 00000000000..e7a9219ba9c --- /dev/null +++ b/frameworks/Ruby/sinatra/config/puma.rb @@ -0,0 +1,3 @@ +before_fork do + ActiveRecord::Base.connection_handler.clear_active_connections! +end diff --git a/frameworks/Ruby/sinatra/db.rb b/frameworks/Ruby/sinatra/db.rb new file mode 100644 index 00000000000..0975ea9702c --- /dev/null +++ b/frameworks/Ruby/sinatra/db.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +def connect(dbtype) + Bundler.require(dbtype) # Load database-specific modules + + opts = { + username: 'benchmarkdbuser', + password: 'benchmarkdbpass', + host: 'tfb-database', + database: 'hello_world' + } + + if dbtype == :mysql + opts[:adapter] = 'trilogy' + opts[:ssl] = true + opts[:ssl_mode] = 4 # Trilogy::SSL_PREFERRED_NOVERIFY + opts[:tls_min_version] = 3 # Trilogy::TLS_VERSION_12 + else + opts[:adapter] = 'postgresql' + end + + # Determine threading/thread pool size and timeout + if defined?(Puma) + opts[:pool] = ENV.fetch('MAX_THREADS') + opts[:checkout_timeout] = 10 + else + opts[:pool] = 512 + end + + ActiveRecord::Base.establish_connection(opts) + ActiveRecord::Base.logger = nil +end + +connect ENV.fetch('DBTYPE').to_sym + +# Define ORM models +class World < ActiveRecord::Base + self.table_name = name + + alias_attribute(:randomNumber, :randomnumber) \ + if connection.adapter_name.downcase.start_with?('postgres') + + if connection.adapter_name.downcase.start_with?('trilogy') + def self.upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) + # On MySQL Batch updates verification isn't supported yet by TechEmpower. + # https://github.com/TechEmpower/FrameworkBenchmarks/issues/5983 + attributes.each do |attrs| + where(id: attrs[:id]).update_all(randomNumber: attrs[:randomNumber]) + end + end + end +end + +class Fortune < ActiveRecord::Base + self.table_name = name +end diff --git a/frameworks/Ruby/sinatra/hello_world.rb b/frameworks/Ruby/sinatra/hello_world.rb index 3c5a96ba2a4..41c5f7a9cae 100644 --- a/frameworks/Ruby/sinatra/hello_world.rb +++ b/frameworks/Ruby/sinatra/hello_world.rb @@ -1,7 +1,22 @@ # frozen_string_literal: true +require 'bundler/setup' +Bundler.require(:default) # Load core modules + +require_relative 'db' +require 'time' # Our Rack application to be executed by rackup class HelloWorld < Sinatra::Base + MAX_PK = 10_000 + ID_RANGE = (1..MAX_PK).freeze + ALL_IDS = ID_RANGE.to_a + QUERIES_MIN = 1 + QUERIES_MAX = 500 + + DATE_HEADER = 'Date' + SERVER_HEADER = 'Server' + SERVER_STRING = 'Sinatra' + configure do # Static file serving is ostensibly disabled in modular mode but Sinatra # still calls an expensive Proc on every request... @@ -15,36 +30,17 @@ class HelloWorld < Sinatra::Base # Only add the charset parameter to specific content types per the requirements set :add_charset, [mime_type(:html)] - end - helpers do - def bounded_queries - queries = params[:queries].to_i - queries.clamp(QUERIES_MIN, QUERIES_MAX) - end - - def json(data) - content_type :json - data.to_json - end + # Disable logging middleware + set :logging, nil - # Return a random number between 1 and MAX_PK - def rand1 - rand(MAX_PK).succ - end + # Set root once instead executing the proc on every request + set :root, File.expand_path(__dir__) end - after do - response['Date'] = Time.now.httpdate - end if defined?(Falcon) || defined?(Puma) || defined?(Agoo) - - after do - response['Server'] = SERVER_STRING - end if SERVER_STRING - # Test type 1: JSON serialization get '/json' do - json message: 'Hello, World!' + render_json message: 'Hello, World!' end # Test type 2: Single database query @@ -54,7 +50,7 @@ def rand1 World.find(rand1).attributes end - json world + render_json world end # Test type 3: Multiple database queries @@ -67,7 +63,7 @@ def rand1 end end - json worlds + render_json worlds end # Test type 4: Fortunes @@ -75,13 +71,13 @@ def rand1 @fortunes = ActiveRecord::Base.with_connection do Fortune.all end.to_a - @fortunes << Fortune.new( - id: 0, - message: 'Additional fortune added at request time.' - ) + fortune = Fortune.new + fortune.id = 0 + fortune.message = "Additional fortune added at request time." + @fortunes << fortune @fortunes.sort_by!(&:message) - erb :fortunes, layout: true + render_html :fortunes end # Test type 5: Database updates @@ -100,12 +96,51 @@ def rand1 ActiveRecord::Base.with_connection do World.upsert_all(worlds) end - json worlds + render_json worlds end # Test type 6: Plaintext get '/plaintext' do + render_text 'Hello, World!' + end + + private + + def render_json(data) + add_headers + content_type :json + JSON.generate(data) + end + + def render_html(template) + add_headers + render :erb, template, layout: true + end + + def render_text(content) + add_headers content_type :text - 'Hello, World!' + content + end + + def bounded_queries + queries = params[:queries].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end + + # Return a random number between 1 and MAX_PK + def rand1 + rand(MAX_PK).succ + end + + if defined?(Puma) + def add_headers + response[SERVER_HEADER] = SERVER_STRING + response[DATE_HEADER] = Time.now.httpdate + end + else + def add_headers + response[SERVER_HEADER] = SERVER_STRING + end end end diff --git a/frameworks/Ruby/sinatra/sinatra-iodine.dockerfile b/frameworks/Ruby/sinatra/sinatra-iodine.dockerfile new file mode 100644 index 00000000000..41db8e8a975 --- /dev/null +++ b/frameworks/Ruby/sinatra/sinatra-iodine.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:4.0 + +ENV RUBY_YJIT_ENABLE=1 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +ADD ./ /sinatra +WORKDIR /sinatra + +ENV BUNDLE_WITH=mysql:iodine +RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile + +ENV APP_ENV=production +ENV DBTYPE=mysql + +EXPOSE 8080 + +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile index 7dbd84dfeca..ac1d2ae621f 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 @@ -18,4 +18,4 @@ ENV DBTYPE=postgresql EXPOSE 8080 -CMD bundle exec iodine -p 8080 -w $(ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1) +CMD bundle exec iodine -p 8080 -w $(($(nproc)*5/4)) diff --git a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile index 61cb25c2551..33600c282ca 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile @@ -1,6 +1,7 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -16,9 +17,10 @@ RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile ENV APP_ENV=production ENV DBTYPE=postgresql -ENV WEB_CONCURRENCY=auto +ENV MIN_THREADS=5 ENV MAX_THREADS=5 EXPOSE 8080 -CMD bundle exec puma -b tcp://0.0.0.0:8080 +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + bundle exec puma -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/sinatra.dockerfile b/frameworks/Ruby/sinatra/sinatra.dockerfile index f6082c07919..b1079a7c597 100644 --- a/frameworks/Ruby/sinatra/sinatra.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra.dockerfile @@ -1,6 +1,7 @@ -FROM ruby:4.0-rc +FROM ruby:4.0 ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_MN_THREADS=1 # Use Jemalloc RUN apt-get update && \ @@ -16,9 +17,10 @@ RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile ENV APP_ENV=production ENV DBTYPE=mysql -ENV WEB_CONCURRENCY=auto +ENV MIN_THREADS=5 ENV MAX_THREADS=5 EXPOSE 8080 -CMD bundle exec puma -b tcp://0.0.0.0:8080 +CMD export WEB_CONCURRENCY=$(($(nproc)*5/4)) && \ + bundle exec puma -b tcp://0.0.0.0:8080 diff --git a/frameworks/Rust/astra/Cargo.toml b/frameworks/Rust/astra/Cargo.toml old mode 100755 new mode 100644 diff --git a/frameworks/Rust/astra/benchmark_config.json b/frameworks/Rust/astra/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/axum/Cargo.lock b/frameworks/Rust/axum/Cargo.lock index ae79df4e8d4..bf37e0e46bc 100644 --- a/frameworks/Rust/axum/Cargo.lock +++ b/frameworks/Rust/axum/Cargo.lock @@ -1954,9 +1954,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", diff --git a/frameworks/Rust/axum/README.md b/frameworks/Rust/axum/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/axum/benchmark_config.json b/frameworks/Rust/axum/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/chopin/.gitignore b/frameworks/Rust/chopin/.gitignore new file mode 100644 index 00000000000..b2313282176 --- /dev/null +++ b/frameworks/Rust/chopin/.gitignore @@ -0,0 +1,3 @@ +/target/ +.env +.DS_Store diff --git a/frameworks/Rust/chopin/Cargo.lock b/frameworks/Rust/chopin/Cargo.lock new file mode 100644 index 00000000000..8eed01fa85a --- /dev/null +++ b/frameworks/Rust/chopin/Cargo.lock @@ -0,0 +1,4713 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "annotate-snippets" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-compression" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68650b7df54f0293fd061972a0fb05aaf4fc0879d3b3d21a638a182c5c543b9f" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core", + "axum-macros", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "multer", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta 0.1.4", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chopin-benchmark" +version = "0.2.1" +dependencies = [ + "axum", + "bytes", + "chopin-core", + "rand 0.9.2", + "sea-orm", + "serde", + "tokio", + "yarte", +] + +[[package]] +name = "chopin-core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63a63306dbc5dd2187456f0c3a6d4c7e9cc83a8842d29e7c69a8ed6472ea02a" +dependencies = [ + "argon2", + "async-trait", + "axum", + "bytes", + "chrono", + "dotenvy", + "http-body", + "httpdate", + "hyper", + "hyper-util", + "jsonwebtoken", + "mimalloc", + "mime_guess", + "reqwest", + "ring", + "rustls", + "sea-orm", + "sea-orm-migration", + "serde", + "serde_json", + "serde_urlencoded", + "socket2 0.5.10", + "sonic-rs", + "thiserror", + "tokio", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "utoipa", + "utoipa-scalar", + "uuid", + "validator", +] + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compression-codecs" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.115", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.115", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.115", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "faststr" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca7d44d22004409a61c393afb3369c8f7bb74abcae49fe249ee01dcc3002113" +dependencies = [ + "bytes", + "rkyv 0.8.15", + "serde", + "simdutf8", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "hdrhistogram" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "byteorder", + "num-traits", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "inherent" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.181" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", + "redox_syscall 0.7.1", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mimalloc" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "native-tls" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5d26952a508f321b4d3d2e80e78fc2603eaefcdf0c30783867f19586518bdc" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pgvector" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" +dependencies = [ + "serde", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.115", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", + "version_check", + "yansi", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive 0.1.4", +] + +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive 0.3.1", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rancor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +dependencies = [ + "ptr_meta 0.3.1", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rend" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta 0.1.4", + "rend 0.4.2", + "rkyv_derive 0.7.46", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70" +dependencies = [ + "bytes", + "hashbrown 0.16.1", + "indexmap", + "munge", + "ptr_meta 0.3.1", + "rancor", + "rend 0.5.3", + "rkyv_derive 0.8.15", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust_decimal" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv 0.7.46", + "serde", + "serde_json", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sea-bae" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" +dependencies = [ + "heck 0.4.1", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "sea-orm" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d945f62558fac19e5988680d2fdf747b734c2dbc6ce2cb81ba33ed8dde5b103" +dependencies = [ + "async-stream", + "async-trait", + "bigdecimal", + "chrono", + "derive_more 2.1.1", + "futures-util", + "log", + "ouroboros", + "pgvector", + "rust_decimal", + "sea-orm-macros", + "sea-query", + "sea-query-binder", + "serde", + "serde_json", + "sqlx", + "strum", + "thiserror", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sea-orm-cli" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94492e2ab6c045b4cc38013809ce255d14c3d352c9f0d11e6b920e2adc948ad" +dependencies = [ + "chrono", + "clap", + "dotenvy", + "glob", + "regex", + "sea-schema", + "sqlx", + "tokio", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "sea-orm-macros" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c2e64a50a9cc8339f10a27577e10062c7f995488e469f2c95762c5ee847832" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "sea-bae", + "syn 2.0.115", + "unicode-ident", +] + +[[package]] +name = "sea-orm-migration" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7315c0cadb7e60fb17ee2bb282aa27d01911fc2a7e5836ec1d4ac37d19250bb4" +dependencies = [ + "async-trait", + "clap", + "dotenvy", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sea-query" +version = "0.32.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5d1c518eaf5eda38e5773f902b26ab6d5e9e9e2bb2349ca6c64cf96f80448c" +dependencies = [ + "bigdecimal", + "chrono", + "inherent", + "ordered-float", + "rust_decimal", + "sea-query-derive", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "sea-query-binder" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" +dependencies = [ + "bigdecimal", + "chrono", + "rust_decimal", + "sea-query", + "serde_json", + "sqlx", + "time", + "uuid", +] + +[[package]] +name = "sea-query-derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae0cbad6ab996955664982739354128c58d16e126114fe88c2a493642502aab" +dependencies = [ + "darling", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.115", + "thiserror", +] + +[[package]] +name = "sea-schema" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2239ff574c04858ca77485f112afea1a15e53135d3097d0c86509cef1def1338" +dependencies = [ + "futures", + "sea-query", + "sea-query-binder", + "sea-schema-derive", + "sqlx", +] + +[[package]] +name = "sea-schema-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "sonic-number" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a74044c092f4f43ca7a6cfd62854cf9fb5ac8502b131347c990bf22bef1dfe" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "sonic-rs" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4425ea8d66ec950e0a8f2ef52c766cc3d68d661d9a0845c353c40833179fd866" +dependencies = [ + "ahash 0.8.12", + "bumpalo", + "bytes", + "cfg-if", + "faststr", + "itoa", + "ref-cast", + "ryu", + "serde", + "simdutf8", + "sonic-number", + "sonic-simd", + "thiserror", +] + +[[package]] +name = "sonic-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5707edbfb34a40c9f2a55fa09a49101d9fec4e0cc171ce386086bd9616f34257" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bigdecimal", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "once_cell", + "percent-encoding", + "rust_decimal", + "rustls", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror", + "time", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", + "webpki-roots 0.26.11", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.115", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.115", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bigdecimal", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "rust_decimal", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bigdecimal", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "num-bigint", + "once_cell", + "rand 0.8.5", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "hdrhistogram", + "indexmap", + "pin-project-lite", + "slab", + "sync_wrapper", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "async-compression", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "iri-string", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "uuid", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.115", + "uuid", +] + +[[package]] +name = "utoipa-scalar" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59559e1509172f6b26c1cdbc7247c4ddd1ac6560fe94b584f81ee489b141f719" +dependencies = [ + "axum", + "serde", + "serde_json", + "utoipa", +] + +[[package]] +name = "uuid" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "getrandom 0.4.1", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "v_eval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9" +dependencies = [ + "regex", + "syn 1.0.109", +] + +[[package]] +name = "v_htmlescape" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" + +[[package]] +name = "validator" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b4a29d8709210980a09379f27ee31549b73292c87ab9899beee1c0d3be6303" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac855a2ce6f843beb229757e6e570a42e837bcb15e5f449dd48d5747d41bf77" +dependencies = [ + "darling", + "once_cell", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.115", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease 0.2.37", + "syn 2.0.115", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease 0.2.37", + "proc-macro2", + "quote", + "syn 2.0.115", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] + +[[package]] +name = "yarte" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfce1df93f3b16e5272221a559e60bbbaaa71dbc042a43996d223e51a690aab2" +dependencies = [ + "yarte_derive", + "yarte_helpers", +] + +[[package]] +name = "yarte_codegen" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a79312078b97a195de91a8c1457c2e0d7abd97e6e605f3cdeb01b3c105d2cff" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "yarte_helpers", + "yarte_hir", +] + +[[package]] +name = "yarte_derive" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b296edd7e1a81717b6f794baa2de8dfe89646050847161550b2d963b3ca6fe80" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "yarte_codegen", + "yarte_helpers", + "yarte_hir", + "yarte_parser", +] + +[[package]] +name = "yarte_helpers" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d1076f8cee9541ea5ffbecd9102f751252c91f085e7d30a18a3ce805ebd3ee" +dependencies = [ + "dtoa", + "itoa", + "prettyplease 0.1.25", + "serde", + "syn 1.0.109", + "toml", + "v_htmlescape", +] + +[[package]] +name = "yarte_hir" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee42d2f704a3b1d8bc111d47a705d1302a0943d85e4c230f4e8300ee0dde4a6" +dependencies = [ + "derive_more 0.99.20", + "proc-macro2", + "quote", + "syn 1.0.109", + "v_eval", + "v_htmlescape", + "yarte_helpers", + "yarte_parser", +] + +[[package]] +name = "yarte_parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "538f72049cf7104e12d5c444048d112cb8fc788a31308afd912442a381ba860c" +dependencies = [ + "annotate-snippets", + "derive_more 0.99.20", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", + "unicode-xid", + "yarte_helpers", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/frameworks/Rust/chopin/Cargo.toml b/frameworks/Rust/chopin/Cargo.toml new file mode 100644 index 00000000000..afa41cd0908 --- /dev/null +++ b/frameworks/Rust/chopin/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +members = ["benchmark"] +resolver = "2" + +[workspace.package] +version = "0.2.1" +edition = "2021" +license = "MIT" + +[profile.release] +opt-level = 3 +lto = "fat" +codegen-units = 1 +strip = true +panic = "abort" +overflow-checks = false +incremental = false diff --git a/frameworks/Rust/chopin/README.md b/frameworks/Rust/chopin/README.md new file mode 100644 index 00000000000..e2fdcf4fbee --- /dev/null +++ b/frameworks/Rust/chopin/README.md @@ -0,0 +1,24 @@ +# Chopin — TechEmpower Framework Benchmarks + +[Chopin](https://crates.io/crates/chopin-core) is a high-level Rust web framework built on Axum and Hyper. + +This benchmark uses `chopin-core` v0.3.3 with the `perf` feature: +- **FastRoute** for `/json` and `/plaintext` — zero-alloc pre-computed responses (~35ns/req) +- **sonic-rs** SIMD-accelerated JSON serialization for all DB responses via `chopin_core::json::to_bytes()` +- **mimalloc** high-performance allocator (via `perf` feature) +- **start_multicore** — per-core `current_thread` tokio runtime with `SO_REUSEPORT` +- **ChopinService** — FastRoute match bypasses Axum middleware entirely +- **tokio-postgres** raw driver for database queries + +## Test URLs + +| Test | URL | +|------|-----| +| JSON | /json | +| Plaintext | /plaintext | +| Single query | /db | +| Multiple queries | /queries?q= | +| Fortunes | /fortunes | +| Updates | /updates?q= | +| Cached queries | /cached-queries?q= | + diff --git a/frameworks/Rust/chopin/benchmark/Cargo.toml b/frameworks/Rust/chopin/benchmark/Cargo.toml new file mode 100644 index 00000000000..d0a7f7b7aae --- /dev/null +++ b/frameworks/Rust/chopin/benchmark/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "chopin-benchmark" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "TechEmpower Framework Benchmarks — Chopin" + +[[bin]] +name = "chopin-benchmark" +path = "src/main.rs" + +[dependencies] +axum = { version = "0.8", default-features = false, features = ["http1", "json", "tokio"] } +chopin-core = { version = "0.3.5", features = ["perf"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tokio = { version = "1", features = ["rt", "net", "macros"] } +tracing = "0.1" +tracing-subscriber = "0.3" diff --git a/frameworks/Rust/chopin/benchmark/src/main.rs b/frameworks/Rust/chopin/benchmark/src/main.rs new file mode 100644 index 00000000000..f1233f36473 --- /dev/null +++ b/frameworks/Rust/chopin/benchmark/src/main.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use chopin_core::FastRoute; +use serde::Serialize; +use tracing::info; + +#[derive(Serialize)] +struct Message { + message: &'static str, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<(), Box> { + tracing_subscriber::fmt::init(); + + let config = chopin_core::Config::from_env()?; + chopin_core::perf::init_date_cache(); + + // chopin-core 0.3.5+: FastRoute computes headers (Content-Length, Date, Server) per-request. + // TFB compliance is maintained regardless of route type. + let fast_routes = Arc::new([ + // Plaintext: static body, per-request headers + FastRoute::text("/plaintext", b"Hello, World!").get_only(), + // JSON: per-request serialization and per-request headers + FastRoute::json_serialize("/json", || Message { + message: "Hello, World!", + }) + .get_only(), + ]); + + let addr: std::net::SocketAddr = config.server_addr().parse()?; + info!("Starting Chopin server on {}", addr); + + // Empty Router (all routes handled by FastRoute) + let router = chopin_core::Router::new(); + + chopin_core::server::run_reuseport(addr, fast_routes, router, std::future::pending()) + .await?; + + Ok(()) +} \ No newline at end of file diff --git a/frameworks/Rust/chopin/benchmark_config.json b/frameworks/Rust/chopin/benchmark_config.json new file mode 100644 index 00000000000..9d1b759eb2c --- /dev/null +++ b/frameworks/Rust/chopin/benchmark_config.json @@ -0,0 +1,29 @@ +{ + "framework": "chopin", + "maintainers": ["kowito"], + "tests": [ + { + "default": { + "dockerfile": "chopin.dockerfile", + "docker_cmd": "/app/chopin-benchmark", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8000, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "Chopin", + "language": "Rust", + "flavor": "None", + "orm": "None", + "platform": "Rust", + "webserver": "Tokio", + "os": "Linux", + "database_os": "Linux", + "display_name": "Chopin", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/chopin/chopin.dockerfile b/frameworks/Rust/chopin/chopin.dockerfile new file mode 100644 index 00000000000..67f0e7c1327 --- /dev/null +++ b/frameworks/Rust/chopin/chopin.dockerfile @@ -0,0 +1,33 @@ +FROM docker.io/rust:1.91-slim-bookworm AS builder + +RUN apt-get update && apt-get install -y --no-install-recommends \ + pkg-config libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Copy manifests and fetch dependencies first (layer caching) +COPY ./Cargo.toml ./Cargo.lock /build/ +COPY ./benchmark/Cargo.toml /build/benchmark/ +RUN mkdir -p benchmark/src && echo "fn main() {}" > benchmark/src/main.rs \ + && cargo fetch \ + && rm -rf benchmark/src + +# Copy source and templates, then build +COPY ./benchmark/ /build/benchmark/ + +ENV RUSTFLAGS="-C target-cpu=native" +ENV REUSEPORT=true +RUN cargo build --release -p chopin-benchmark + +FROM gcr.io/distroless/cc-debian12 + +# Chopin config: Config::from_env() reads these environment variables +ENV SERVER_HOST=0.0.0.0 +ENV SERVER_PORT=8000 +ENV REUSEPORT=true +ENV ENVIRONMENT=production + +COPY --from=builder /build/target/release/chopin-benchmark /app/chopin-benchmark +EXPOSE 8000 +CMD ["/app/chopin-benchmark"] diff --git a/frameworks/Rust/faf/benchmark_config.json b/frameworks/Rust/faf/benchmark_config.json index 476d9a3dfd6..5a77df91e79 100644 --- a/frameworks/Rust/faf/benchmark_config.json +++ b/frameworks/Rust/faf/benchmark_config.json @@ -5,7 +5,7 @@ "default": { "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "None", "framework": "faf", diff --git a/frameworks/Rust/gotham/README.md b/frameworks/Rust/gotham/README.md index f3717ae9168..4887986c5c9 100644 --- a/frameworks/Rust/gotham/README.md +++ b/frameworks/Rust/gotham/README.md @@ -1,4 +1,4 @@ -# Gotham Benchmarking Test +# [Gotham](https://github.com/gotham-rs/gotham) Benchmarking Test ### Test Type Implementation Source Code diff --git a/frameworks/Rust/gotham/benchmark_config.json b/frameworks/Rust/gotham/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/hotaru/.dockerignore b/frameworks/Rust/hotaru/.dockerignore new file mode 100644 index 00000000000..2ec7158c4f6 --- /dev/null +++ b/frameworks/Rust/hotaru/.dockerignore @@ -0,0 +1,7 @@ +/target +/db +/techempower_submission +/.git +/.gitignore +/README.md +/BENCHMARK_RESULTS.md diff --git a/frameworks/Rust/hotaru/Cargo.lock b/frameworks/Rust/hotaru/Cargo.lock new file mode 100644 index 00000000000..83439c3b701 --- /dev/null +++ b/frameworks/Rust/hotaru/Cargo.lock @@ -0,0 +1,1938 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "ahttpm" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79d5a2ff4c281ccde88732ee3d97bba34b705411eb6c247f287cdfeef956a9b4" +dependencies = [ + "ctor", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "akari" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29fc5ecf6848c1201733fa2ccdbeca413a901aae729c198a0010cc3e3d536e62" +dependencies = [ + "akari_macro", +] + +[[package]] +name = "akari_macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f0321f46e347313a51ecaebfbca8d13c093426b91f3bfb0a964476fb6f9c32" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cc" +version = "1.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec09e802f5081de6157da9a75701d6c713d8dc3ba52571fd4bd25f412644e8a6" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" + +[[package]] +name = "deadpool" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +dependencies = [ + "deadpool-runtime", + "lazy_static", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-postgres" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d697d376cbfa018c23eb4caab1fd1883dd9c906a8c034e8d9a3cb06a7e0bef9" +dependencies = [ + "async-trait", + "deadpool", + "getrandom 0.2.17", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dtor" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hotaru" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad23550ea8946170ff3a019fcd43545e862f7c27f9aa48174a482f020278d9" +dependencies = [ + "ahttpm", + "akari", + "futures", + "hotaru_core", + "hotaru_lib", + "hotaru_meta", + "once_cell", + "regex", + "tokio", +] + +[[package]] +name = "hotaru_bench" +version = "0.1.0" +dependencies = [ + "akari", + "ctor", + "deadpool-postgres", + "hotaru", + "httpdate", + "moka", + "rand 0.8.5", + "serde", + "serde_json", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "hotaru_core" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4100aa58aa87b5066b4144819604ea5dc2cfd0f8389078e9e7ffde1f2076d2" +dependencies = [ + "akari", + "async-trait", + "bytes", + "fnv", + "futures", + "futures-core", + "futures-util", + "hotaru_lib", + "http", + "include_dir", + "once_cell", + "parking_lot", + "regex", + "rustls", + "rustls-pemfile", + "rustls-platform-verifier", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "hotaru_lib" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c006f8b72fc6ea8cd678647eaa5a792e36eab9836b3793fb79e4e4595430e6" +dependencies = [ + "brotli", + "flate2", + "percent-encoding", + "rand 0.9.2", + "zstd", +] + +[[package]] +name = "hotaru_meta" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4473f169efd7e3a7161d8ff659137bb1469c3016525f9de499d748be8c13ede3" +dependencies = [ + "hotaru_lib", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "moka" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac832c50ced444ef6be0767a008b02c106a909ba79d1d830501e94b96f6b7e" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared", + "serde", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" + +[[package]] +name = "postgres-protocol" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee9dd5fe15055d2b6806f4736aa0c9637217074e224bbec46d4041b91bb9491" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.9.2", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b858f82211e84682fecd373f68e1ceae642d8d751a1ebd13f33de6257b3e20" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcea47c8f71744367793f16c2db1f11cb859d28f436bdb4ca9193eb1f787ee42" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.9.2", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fae98cf96deed1b7572272dfc777713c249ae40aa1cf8862e091e8b745f5361" +dependencies = [ + "libredox", + "wasite", + "web-sys", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zerocopy" +version = "0.8.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dafd85c832c1b68bbb4ec0c72c7f6f4fc5179627d2bc7c26b30e4c0cc11e76cc" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb7e4e8436d9db52fbd6625dbf2f45243ab84994a72882ec8227b99e72b439a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/frameworks/Rust/hotaru/Cargo.toml b/frameworks/Rust/hotaru/Cargo.toml new file mode 100644 index 00000000000..e722c76ce10 --- /dev/null +++ b/frameworks/Rust/hotaru/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "hotaru_bench" +version = "0.1.0" +edition = "2024" + +[dependencies] +tokio = { version = "1", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +rand = { version = "0.8", features = ["small_rng"] } +httpdate = "1" + +# Hotaru framework +hotaru = "0.7.7" +akari = "0.2.6" +ctor = "0.4" + +# Database +tokio-postgres = "0.7" +deadpool-postgres = "0.14" +moka = { version = "0.12", features = ["sync"] } diff --git a/frameworks/Rust/hotaru/README.md b/frameworks/Rust/hotaru/README.md new file mode 100644 index 00000000000..b07522312d1 --- /dev/null +++ b/frameworks/Rust/hotaru/README.md @@ -0,0 +1,192 @@ +# Hotaru Framework - TechEmpower Benchmark Implementation + +[Hotaru](https://github.com/Field-of-Dreams-Studio/hotaru) is a lightweight, intuitive full-stack web framework for Rust that emphasizes simplicity and developer experience. + +## Framework Information + +- **Homepage**: https://github.com/Field-of-Dreams-Studio/hotaru +- **Documentation**: https://docs.rs/hotaru +- **Version**: 0.7.7 +- **Language**: Rust +- **Platform**: Tokio async runtime + +## Implemented Tests + +According to the [TechEmpower Framework Benchmarks specification](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview), this implementation includes all 7 required test types: + +### 1. JSON Serialization Test (`/json`) +- **Endpoint**: `GET /json` +- **Response**: `{"message":"Hello, World!"}` +- **Content-Type**: `application/json` +- Tests framework fundamentals including routing, JSON serialization, and response handling + +### 2. Plaintext Test (`/plaintext`) +- **Endpoint**: `GET /plaintext` +- **Response**: `Hello, World!` +- **Content-Type**: `text/plain` +- Tests raw request routing and response generation capabilities + +### 3. Single Database Query Test (`/db`) +- **Endpoint**: `GET /db` +- **Response**: `{"id": 123, "randomNumber": 456}` +- **Content-Type**: `application/json` +- Fetches one random World row (ID 1-10000) from PostgreSQL + +### 4. Multiple Queries Test (`/queries`) +- **Endpoint**: `GET /queries?queries=N` +- **Response**: Array of World objects +- **Constraints**: `queries` parameter clamped to 1-500 +- Performs N database queries and returns results as JSON array + +### 5. Updates Test (`/updates`) +- **Endpoint**: `GET /updates?queries=N` +- **Response**: Array of updated World objects +- **Constraints**: `queries` parameter clamped to 1-500 +- Fetches N random World rows, updates randomNumber field, persists to database + +### 6. Cached Queries Test (`/cached-worlds`) +- **Endpoint**: `GET /cached-worlds?count=N` +- **Response**: Array of World objects +- **Constraints**: `count` parameter clamped to 1-500 +- **Cache**: In-memory cache (moka) pre-warmed with all 10,000 World rows at startup +- Falls back to database on cache miss + +### 7. Fortunes Test (`/fortunes`) +- **Endpoint**: `GET /fortunes` +- **Response**: HTML table of fortunes, sorted by message +- **Content-Type**: `text/html; charset=utf-8` +- Fetches all Fortune rows, adds test fortune, sorts, and renders HTML template + +## Technology Stack + +- **Web Framework**: Hotaru 0.7.7 +- **Template Engine**: Akari (Hotaru's built-in template system) +- **Database**: PostgreSQL via tokio-postgres +- **Connection Pool**: deadpool-postgres +- **Cache**: moka (in-memory, 10,000 entry capacity) +- **Async Runtime**: Tokio + +## Running Locally + +### Prerequisites +- Rust 1.93.0+ +- PostgreSQL database with TechEmpower schema + +### Run the Server + +```bash +cd frameworks/Rust/hotaru +cargo run --release +``` + +The server will start on `http://0.0.0.0:8080` + +### Environment Variables + +```bash +DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@localhost/hello_world +DB_POOL_SIZE=56 # Database connection pool size +``` + +## Test Endpoints + +```bash +# JSON serialization +curl http://localhost:8080/json + +# Plaintext +curl http://localhost:8080/plaintext + +# Single database query +curl http://localhost:8080/db + +# Multiple queries (10 queries) +curl "http://localhost:8080/queries?queries=10" + +# Updates (5 updates) +curl "http://localhost:8080/updates?queries=5" + +# Cached queries (100 from cache) +curl "http://localhost:8080/cached-worlds?count=100" + +# Fortunes (HTML) +curl http://localhost:8080/fortunes +``` + +## Performance + +Benchmark results on TechEmpower infrastructure (512 concurrent connections): + +- **Plaintext**: ~290,802 requests/sec +- **JSON**: ~290,802 requests/sec +- **Cached Queries (1)**: ~290,802 requests/sec +- **Cached Queries (20)**: ~191,349 requests/sec +- **Cached Queries (100)**: ~87,395 requests/sec + +Average latency: 1.94-6.21ms under heavy load + +## Implementation Details + +### Architecture + +- **Lazy Static App**: Hotaru app initialized once using `Lazy` +- **Cache Warm-up**: All 10,000 World records pre-loaded into moka cache at startup +- **Connection Pooling**: deadpool-postgres with configurable pool size (default: 56) +- **Zero-Copy Caching**: Uses `Arc` for efficient cache sharing + +### HTTP Headers + +All responses include required TechEmpower headers: +- `Server: hotaru` +- `Date: ` +- Appropriate `Content-Type` headers + +### Database Schema + +```sql +-- World table (10,000 rows, IDs 1-10000) +CREATE TABLE World ( + id integer NOT NULL, + randomNumber integer NOT NULL, + PRIMARY KEY (id) +); + +-- Fortune table +CREATE TABLE Fortune ( + id integer NOT NULL, + message varchar(2048) NOT NULL, + PRIMARY KEY (id) +); +``` + +## File Structure + +``` +frameworks/Rust/hotaru/ +├── Cargo.toml # Dependencies and build config +├── README.md # This file +├── benchmark_config.json # TFB configuration +├── hotaru.dockerfile # Docker build instructions +├── setup.py # TFB setup script +├── src/ +│ ├── main.rs # Hotaru server and endpoints +│ ├── database.rs # Database pool, cache, and queries +│ ├── models.rs # Data models (World, Fortune) +│ └── utils.rs # Helper functions +└── templates/ + └── fortunes_hotaru.html # Fortune HTML template (Akari syntax) +``` + +## Notes + +- Uses Rust edition 2024 +- All dependencies from crates.io (no local path dependencies) +- Follows TechEmpower requirements for header handling, query clamping, and HTML escaping +- Cache implementation uses lazy population on miss +- Prepared statements cached for all database queries + +## Links + +- **Hotaru Framework**: https://github.com/Field-of-Dreams-Studio/hotaru +- **Documentation**: https://docs.rs/hotaru +- **TechEmpower Benchmarks**: https://www.techempower.com/benchmarks/ diff --git a/frameworks/Rust/hotaru/README_SUBMISSION.md b/frameworks/Rust/hotaru/README_SUBMISSION.md new file mode 100644 index 00000000000..330f3c17286 --- /dev/null +++ b/frameworks/Rust/hotaru/README_SUBMISSION.md @@ -0,0 +1,72 @@ +# Hotaru TechEmpower Benchmark Submission + +This directory contains the TechEmpower Framework Benchmarks submission for Hotaru. + +## Files Overview + +- `benchmark_config.json` - Main benchmark configuration (updated to R23 schema) +- `hotaru.dockerfile` - Multi-stage Docker build for the benchmark +- `Cargo.toml` - Rust dependencies and project config +- `src/` - Source code with all benchmark endpoints +- `templates/` - Templates for the fortunes test +- `setup.py` - Minimal helper (not used by current toolset) + +## Configuration Summary + +### Endpoints Implemented +- `/json` - JSON serialization test +- `/plaintext` - Plaintext response test +- `/db` - Single database query +- `/queries?queries=N` - Multiple database queries (1-500) +- `/updates?queries=N` - Multiple database updates (1-500) +- `/cached-worlds?count=N` - Cached query test (1-500) +- `/fortunes` - Fortune cookie test with HTML rendering + +### Key Configuration Details +- **Framework**: Hotaru +- **Language**: Rust +- **Platform**: Rust +- **Database**: PostgreSQL +- **ORM**: Raw SQL +- **Port**: 8080 +- **Docker Command**: `/app/server` + +## Verified Against Local TFB Toolset + +### Schema Notes +- `dockerfile` and `docker_cmd` are supported by the toolset (see `toolset/utils/docker_helper.py`). +- `cached_query_url` is the correct key for cached queries (see `toolset/test_types/cached-query/cached-query.py`). +- All required metadata fields are present (approach, classification, database, etc.). + +### Parameter Names +- Query tests use `?queries=` (standard TFB convention) +- Cached query uses `?count=` (matches implementation in `src/main.rs`) + +## Running Locally with TFB Toolset + +1. Clone TechEmpower/FrameworkBenchmarks repo +2. Copy this directory to `frameworks/Rust/hotaru/` +3. Configure `benchmark.cfg` in TFB root: + ```ini + client_host=localhost + client_identity_file=/Users/yourusername/.ssh/id_rsa + client_user=yourusername + + database_host=localhost + database_identity_file=/Users/yourusername/.ssh/id_rsa + database_user=yourusername + + server_host=localhost + ``` +4. Run verification: + ```bash + ./toolset/run-tests.py --mode verify --test hotaru + ``` + +## Environment Variables + +The Dockerfile sets: +- `DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world` +- `DB_POOL_SIZE=56` + +These match TFB's standard database configuration. diff --git a/frameworks/Rust/hotaru/benchmark_config.json b/frameworks/Rust/hotaru/benchmark_config.json new file mode 100644 index 00000000000..580cb429722 --- /dev/null +++ b/frameworks/Rust/hotaru/benchmark_config.json @@ -0,0 +1,33 @@ +{ + "framework": "hotaru", + "tests": [ + { + "default": { + "dockerfile": "hotaru.dockerfile", + "docker_cmd": "/app/server", + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-worlds?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Hotaru", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Hotaru", + "os": "Linux", + "database_os": "Linux", + "display_name": "Hotaru", + "notes": "", + "versus": "actix" + } + } + ] +} diff --git a/frameworks/Rust/hotaru/hotaru.dockerfile b/frameworks/Rust/hotaru/hotaru.dockerfile new file mode 100644 index 00000000000..077f1d3df72 --- /dev/null +++ b/frameworks/Rust/hotaru/hotaru.dockerfile @@ -0,0 +1,22 @@ +FROM rust:1.93.0 as builder + +WORKDIR /app +COPY Cargo.toml ./ +COPY src ./src +COPY templates ./templates + +RUN cargo build --release + +FROM debian:bookworm-slim +WORKDIR /app + +RUN apt-get update && apt-get install -y libpq5 && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /app/target/release/hotaru_bench /app/server +COPY templates /app/templates + +ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world +ENV DB_POOL_SIZE=56 + +EXPOSE 8080 +CMD ["/app/server"] diff --git a/frameworks/Rust/hotaru/setup.py b/frameworks/Rust/hotaru/setup.py new file mode 100755 index 00000000000..6f793f47dbc --- /dev/null +++ b/frameworks/Rust/hotaru/setup.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +import os +import subprocess +import sys + +def main() -> int: + # Minimal helper for manual use; not required by current TFB toolset. + cmd = os.environ.get("TFB_COMMAND", "/app/server") + if os.path.exists(cmd) and os.access(cmd, os.X_OK): + os.execv(cmd, [cmd]) + return subprocess.call([ + "cargo", + "run", + "--release", + "--features", + "hotaru_server", + ]) + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/frameworks/Rust/hotaru/src/database.rs b/frameworks/Rust/hotaru/src/database.rs new file mode 100644 index 00000000000..965890ee6f9 --- /dev/null +++ b/frameworks/Rust/hotaru/src/database.rs @@ -0,0 +1,105 @@ +use crate::models::{Fortune, World}; +use deadpool_postgres::{GenericClient, Manager, Pool}; +use moka::sync::Cache; +use std::env; +use std::sync::Arc; +use tokio_postgres::NoTls; + +pub const SQL_SELECT_WORLD: &str = "SELECT id, randomNumber FROM World WHERE id = $1"; +pub const SQL_SELECT_FORTUNES: &str = "SELECT id, message FROM Fortune"; +pub const SQL_UPDATE_WORLD: &str = "UPDATE World SET randomNumber = $1 WHERE id = $2"; +pub const SQL_SELECT_CACHED_WORLD: &str = "SELECT id, randomNumber FROM World WHERE id = $1"; +pub const SQL_SELECT_ALL_CACHED: &str = "SELECT id, randomNumber FROM World"; + +pub type DbPool = Pool; +pub type WorldCache = Arc>>; + +pub fn create_pool() -> DbPool { + let db_url = env::var("DATABASE_URL") + .unwrap_or_else(|_| "postgres://benchmarkdbuser:benchmarkdbpass@localhost/hello_world".to_string()); + let pool_size = env::var("DB_POOL_SIZE") + .ok() + .and_then(|value| value.parse::().ok()) + .unwrap_or(56); + + let pg_config: tokio_postgres::Config = db_url + .parse() + .expect("Invalid DATABASE_URL"); + + let manager = Manager::new(pg_config, NoTls); + Pool::builder(manager) + .max_size(pool_size) + .build() + .expect("Failed to build database pool") +} + +pub fn create_cache() -> WorldCache { + Arc::new(Cache::new(10_000)) +} + +pub async fn warm_cache(pool: &DbPool, cache: &WorldCache) -> Result<(), Box> { + let client = pool.get().await?; + let stmt = client.prepare_cached(SQL_SELECT_ALL_CACHED).await?; + let rows = client.query(&stmt, &[]).await?; + + for row in rows { + let world = World { + id: row.get(0), + random_number: row.get(1), + }; + cache.insert(world.id, Arc::new(world)); + } + + Ok(()) +} + +pub async fn fetch_world_by_id(client: &C, id: i32) -> Result +where + C: GenericClient + Sync, +{ + let stmt = client.prepare_cached(SQL_SELECT_WORLD).await?; + let row = client.query_one(&stmt, &[&id]).await?; + Ok(World { + id: row.get(0), + random_number: row.get(1), + }) +} + +pub async fn fetch_cached_world_by_id(client: &C, id: i32) -> Result +where + C: GenericClient + Sync, +{ + let stmt = client.prepare_cached(SQL_SELECT_CACHED_WORLD).await?; + let row = client.query_one(&stmt, &[&id]).await?; + Ok(World { + id: row.get(0), + random_number: row.get(1), + }) +} + +pub async fn fetch_all_fortunes(client: &C) -> Result, tokio_postgres::Error> +where + C: GenericClient + Sync, +{ + let stmt = client.prepare_cached(SQL_SELECT_FORTUNES).await?; + let rows = client.query(&stmt, &[]).await?; + let mut fortunes = Vec::with_capacity(rows.len()); + for row in rows { + fortunes.push(Fortune { + id: row.get(0), + message: row.get(1), + }); + } + Ok(fortunes) +} + +pub async fn update_world(client: &C, world: &World) -> Result<(), tokio_postgres::Error> +where + C: GenericClient + Sync, +{ + let stmt = client.prepare_cached(SQL_UPDATE_WORLD).await?; + client + .execute(&stmt, &[&world.random_number, &world.id]) + .await?; + Ok(()) +} diff --git a/frameworks/Rust/hotaru/src/main.rs b/frameworks/Rust/hotaru/src/main.rs new file mode 100644 index 00000000000..211053b7bbe --- /dev/null +++ b/frameworks/Rust/hotaru/src/main.rs @@ -0,0 +1,235 @@ +use serde::{Deserialize, Serialize}; + +mod models; +mod utils; +mod database; + +#[derive(Serialize, Deserialize)] +struct Message { + message: String, +} + +// Hotaru implementation +mod hotaru_impl { + use super::{database, models::Fortune, models::World, utils, Message}; + use akari::Value; + use hotaru::http::*; + use hotaru::hotaru_core::http::start_line::HttpStartLine; + use hotaru::prelude::*; + use serde::Serialize; + use std::collections::HashMap; + use std::sync::Arc; + use std::time::SystemTime; + use database::{DbPool, WorldCache}; + + #[derive(Clone)] + struct FortuneView { + id: i32, + message: String, + } + + impl From for Value { + fn from(world: World) -> Self { + object!({ + id: world.id, + randomNumber: world.random_number, + }) + } + } + + impl From for Value { + fn from(fortune: FortuneView) -> Self { + object!({ + id: fortune.id, + message: fortune.message, + }) + } + } + + pub static APP: SApp = Lazy::new(|| { + let pool = database::create_pool(); + let cache = database::create_cache(); + let runtime = tokio::runtime::Runtime::new().expect("Failed to create runtime"); + if let Err(err) = runtime.block_on(database::warm_cache(&pool, &cache)) { + eprintln!("Failed to warm cache at startup: {err}"); + } + + App::new() + .binding("0.0.0.0:8080") + .set_statics("db_pool", pool) + .set_statics("world_cache", cache) + .build() + }); + + fn pool_from(req: &HttpContext) -> DbPool { + req.app() + .expect("Hotaru app not available") + .statics() + .get::("db_pool") + .expect("Database pool missing") + .clone() + } + + fn cache_from(req: &HttpContext) -> WorldCache { + req.app() + .expect("Hotaru app not available") + .statics() + .get::("world_cache") + .expect("World cache missing") + .clone() + } + + fn append_fortune(mut fortunes: Vec) -> Vec { + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + fortunes + } + + fn with_standard_headers(response: HttpResponse) -> HttpResponse { + let date = httpdate::fmt_http_date(SystemTime::now()); + response + .add_header("Server", "hotaru") + .add_header("Date", date) + } + + fn json_response_direct(data: &T) -> HttpResponse { + let json_bytes = serde_json::to_vec(data).expect("JSON serialization failed"); + let start_line = HttpStartLine::new_response(HttpVersion::Http11, StatusCode::OK); + let mut meta = HttpMeta::new(start_line, HashMap::new()); + meta.set_content_type(HttpContentType::ApplicationJson()); + with_standard_headers(HttpResponse::new(meta, HttpBody::Binary(json_bytes))) + } + + endpoint! { + APP.url("/json"), + pub json_endpoint { + json_response_direct(&Message { + message: "Hello, World!".to_string(), + }) + } + } + + endpoint! { + APP.url("/plaintext"), + pub plaintext_endpoint { + with_standard_headers(text_response("Hello, World!")) + } + } + + endpoint! { + APP.url("/db"), + pub db_endpoint { + let pool = pool_from(&req); + let client = pool.get().await.expect("DB pool error"); + let id = utils::random_id(); + let world = database::fetch_world_by_id(&client, id) + .await + .expect("DB query failed"); + + json_response_direct(&world) + } + } + + endpoint! { + APP.url("/queries"), + pub queries_endpoint { + let count = utils::parse_query_count(req.query("queries").as_deref()); + let pool = pool_from(&req); + let client = pool.get().await.expect("DB pool error"); + + let mut worlds = Vec::with_capacity(count); + for _ in 0..count { + let id = utils::random_id(); + let world = database::fetch_world_by_id(&client, id) + .await + .expect("DB query failed"); + worlds.push(world); + } + + json_response_direct(&worlds) + } + } + + endpoint! { + APP.url("/updates"), + pub updates_endpoint { + let count = utils::parse_query_count(req.query("queries").as_deref()); + let pool = pool_from(&req); + let client = pool.get().await.expect("DB pool error"); + + let mut worlds = Vec::with_capacity(count); + for _ in 0..count { + let id = utils::random_id(); + let mut world = database::fetch_world_by_id(&client, id) + .await + .expect("DB query failed"); + world.random_number = utils::random_id(); + database::update_world(&client, &world) + .await + .expect("DB update failed"); + worlds.push(world); + } + + json_response_direct(&worlds) + } + } + + endpoint! { + APP.url("/cached-worlds"), + pub cached_worlds_endpoint { + let count = utils::parse_query_count(req.query("count").as_deref()); + let pool = pool_from(&req); + let cache = cache_from(&req); + let client = pool.get().await.expect("DB pool error"); + + let mut worlds = Vec::with_capacity(count); + for _ in 0..count { + let id = utils::random_id(); + if let Some(world) = cache.get(&id) { + worlds.push(world.as_ref().clone()); + } else { + let world = database::fetch_cached_world_by_id(&client, id) + .await + .expect("DB query failed"); + cache.insert(id, Arc::new(world.clone())); + worlds.push(world); + } + } + + json_response_direct(&worlds) + } + } + + endpoint! { + APP.url("/fortunes"), + pub fortunes_endpoint { + let pool = pool_from(&req); + let client = pool.get().await.expect("DB pool error"); + let fortunes = database::fetch_all_fortunes(&client) + .await + .expect("DB query failed"); + let fortunes = append_fortune(fortunes) + .into_iter() + .map(|fortune| FortuneView { + id: fortune.id, + message: utils::escape_html(&fortune.message), + }) + .collect::>(); + + with_standard_headers(akari_render!("fortunes_hotaru.html", fortunes = fortunes)) + } + } + + pub async fn run() { + println!("🔥 Hotaru server running on http://0.0.0.0:8080"); + let _ = APP.clone().run().await; + } +} + +#[tokio::main] +async fn main() { + hotaru_impl::run().await; +} diff --git a/frameworks/Rust/hotaru/src/models.rs b/frameworks/Rust/hotaru/src/models.rs new file mode 100644 index 00000000000..d9159e2157e --- /dev/null +++ b/frameworks/Rust/hotaru/src/models.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub random_number: i32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Debug, Deserialize)] +pub struct QueryParams { + pub queries: Option, +} + +#[derive(Debug, Deserialize)] +pub struct CountParams { + pub count: Option, +} diff --git a/frameworks/Rust/hotaru/src/utils.rs b/frameworks/Rust/hotaru/src/utils.rs new file mode 100644 index 00000000000..397d40a76ec --- /dev/null +++ b/frameworks/Rust/hotaru/src/utils.rs @@ -0,0 +1,53 @@ +use rand::{Rng, SeedableRng}; +use rand::rngs::SmallRng; +use std::cell::RefCell; + +pub const MAX_WORLD_ID: i32 = 10_000; +const MIN_QUERY_COUNT: usize = 1; +const MAX_QUERY_COUNT: usize = 500; + +thread_local! { + static RNG: RefCell = RefCell::new(SmallRng::from_entropy()); +} + +pub fn random_id() -> i32 { + RNG.with(|rng| rng.borrow_mut().gen_range(1..=MAX_WORLD_ID)) +} + +pub fn random_ids(count: usize) -> Vec { + let mut ids = Vec::with_capacity(count); + for _ in 0..count { + ids.push(random_id()); + } + ids +} + +pub fn clamp_query_count(count: Option) -> usize { + let mut value = count.unwrap_or(1) as usize; + if value < MIN_QUERY_COUNT { + value = MIN_QUERY_COUNT; + } else if value > MAX_QUERY_COUNT { + value = MAX_QUERY_COUNT; + } + value +} + +pub fn parse_query_count(value: Option<&str>) -> usize { + let parsed = value.and_then(|raw| raw.parse::().ok()); + clamp_query_count(parsed) +} + +pub fn escape_html(input: &str) -> String { + let mut output = String::with_capacity(input.len()); + for ch in input.chars() { + match ch { + '&' => output.push_str("&"), + '<' => output.push_str("<"), + '>' => output.push_str(">"), + '"' => output.push_str("""), + '\'' => output.push_str("'"), + _ => output.push(ch), + } + } + output +} diff --git a/frameworks/Rust/hotaru/templates/fortunes_hotaru.html b/frameworks/Rust/hotaru/templates/fortunes_hotaru.html new file mode 100644 index 00000000000..47c8266a941 --- /dev/null +++ b/frameworks/Rust/hotaru/templates/fortunes_hotaru.html @@ -0,0 +1,15 @@ + + + + + Fortunes + + + + + -[ for fortune in fortunes ]- + + -[ endfor ]- +
idmessage
-[ output fortune.id ]--[ output fortune.message ]-
+ + diff --git a/frameworks/Rust/hyper/Cargo.lock b/frameworks/Rust/hyper/Cargo.lock index e0f90aad74a..5f69d342b61 100644 --- a/frameworks/Rust/hyper/Cargo.lock +++ b/frameworks/Rust/hyper/Cargo.lock @@ -134,9 +134,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" diff --git a/frameworks/Rust/hyperlane/.cargo/config.toml b/frameworks/Rust/hyperlane/.cargo/config.toml new file mode 100644 index 00000000000..aad0340a99c --- /dev/null +++ b/frameworks/Rust/hyperlane/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "link-arg=-Wl,--as-needed", "-C", "link-arg=-fuse-ld=lld"] diff --git a/frameworks/Rust/hyperlane/Cargo.lock b/frameworks/Rust/hyperlane/Cargo.lock index 9b9082f85bb..9e97dde96a7 100644 --- a/frameworks/Rust/hyperlane/Cargo.lock +++ b/frameworks/Rust/hyperlane/Cargo.lock @@ -38,6 +38,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + [[package]] name = "atoi" version = "2.0.0" @@ -61,9 +67,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" [[package]] name = "bitflags" @@ -112,9 +118,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cfg-if" @@ -122,6 +128,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.0", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -146,11 +163,20 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -187,9 +213,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -250,6 +276,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -274,9 +310,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -310,9 +346,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -325,9 +361,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -335,15 +371,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -363,15 +399,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -380,21 +416,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -404,15 +440,14 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -441,6 +476,20 @@ dependencies = [ "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.0", + "wasip2", + "wasip3", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -454,9 +503,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "hashlink" @@ -514,9 +563,9 @@ dependencies = [ [[package]] name = "http-compress" -version = "3.0.3" +version = "3.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7b163ab0da395ee1f950d547b44ac3b73ed1a351d53454d6ae811e9daa288e" +checksum = "1ab7df1584b69f0865e6a1fa8cca139504f5fc90306856e198c384c5bd449bf8" dependencies = [ "brotli", "flate2", @@ -525,15 +574,15 @@ dependencies = [ [[package]] name = "http-constant" -version = "1.73.0" +version = "5.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7886400d92b0eb2db84097de69ed4649ca9466f4c6b4e8cb342a3b46934a8d43" +checksum = "7ec2708886ccbffc115c6b8510f47de38490a746309e0342255e0abe1eef665d" [[package]] name = "http-type" -version = "5.11.0" +version = "17.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b27d55be58ea8bc2ab73573aeafa68fd50b3098813f83029bcb766f1f1c61b3b" +checksum = "88e85acaf47d5d64c88f2002d9fb3c399f1eea55361ae323d5fef4af26dc1f78" dependencies = [ "hex", "http-compress", @@ -549,35 +598,33 @@ dependencies = [ [[package]] name = "hyperlane" -version = "10.14.0" +version = "18.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6abaa8b50397c4a9d2d0d969ccba9cecdad7bf0fa75c7da0335d6895c3d0ce98" +checksum = "0e2ba2170a04306ba9b323cceae605200cec633c2c6494c538455dbcbe405c24" dependencies = [ - "aho-corasick", "http-type", "inventory", "lombok-macros", "regex", "serde", - "serde_json", ] [[package]] name = "hyperlane-time" -version = "0.7.12" +version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1902a81b87724c226187b798658dd38038afe79eb337735eff39ec5f4d3d30" +checksum = "9b6f580fff377190b818d8c2ef52f68d1296490916da4923fe90287b7c80028c" [[package]] name = "hyperlane_techempower" -version = "0.1.0" +version = "0.1.17" dependencies = [ "futures", "hyperlane", "hyperlane-time", "num_cpus", "once_cell", - "rand 0.9.2", + "rand 0.10.0", "serde", "serde_json", "sqlx", @@ -585,9 +632,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -598,9 +645,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -611,11 +658,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -626,42 +672,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -669,6 +711,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -692,28 +740,30 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "inventory" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +checksum = "009ae045c87e7082cb72dab0ccd01ae075dd00141ddc108f43a0ea150a9e7227" dependencies = [ "rustversion", ] [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "lazy_static" @@ -724,11 +774,17 @@ dependencies = [ "spin", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.177" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libm" @@ -738,13 +794,13 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags", "libc", - "redox_syscall", + "redox_syscall 0.7.0", ] [[package]] @@ -759,9 +815,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -774,15 +830,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lombok-macros" -version = "1.13.13" +version = "2.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf89b026ebf6e1c51f466b40f60f8e90a64305d9cf07268e1adaeceefcb3c7a" +checksum = "febe7caec48f1d3af70c10f5895206873707ef8f957aa8b8dc9e70a1c539421a" dependencies = [ "proc-macro2", "quote", @@ -817,9 +873,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -828,11 +884,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -913,7 +968,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec", "windows-link", ] @@ -939,12 +994,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkcs1" version = "0.7.5" @@ -974,9 +1023,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -990,20 +1039,30 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.41" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1035,6 +1094,17 @@ dependencies = [ "rand_core 0.9.3", ] +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom 0.4.1", + "rand_core 0.10.0", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -1073,6 +1143,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1082,11 +1158,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1113,9 +1198,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", @@ -1139,9 +1224,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "scopeguard" @@ -1149,6 +1234,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1193,15 +1284,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -1223,7 +1314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -1234,16 +1325,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -1259,9 +1351,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "slab" @@ -1520,9 +1612,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.108" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1562,9 +1654,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -1587,9 +1679,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -1615,9 +1707,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -1626,9 +1718,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -1638,9 +1730,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -1649,9 +1741,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -1679,30 +1771,36 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -1740,7 +1838,16 @@ version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.46.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", ] [[package]] @@ -1749,6 +1856,40 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "whoami" version = "1.6.1" @@ -1920,11 +2061,99 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xml" @@ -1934,11 +2163,10 @@ checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -1946,9 +2174,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -1958,18 +2186,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", @@ -2005,9 +2233,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -2016,9 +2244,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -2027,11 +2255,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" diff --git a/frameworks/Rust/hyperlane/Cargo.toml b/frameworks/Rust/hyperlane/Cargo.toml index 40fddf212ec..f6ad6acf0e8 100644 --- a/frameworks/Rust/hyperlane/Cargo.toml +++ b/frameworks/Rust/hyperlane/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hyperlane_techempower" -version = "0.1.0" +version = "0.1.17" readme = "README.md" edition = "2024" authors = ["root@ltpp.vip"] @@ -9,31 +9,24 @@ description = """A lightweight, high-performance, and cross-platform Rust HTTP s keywords = ["http", "request", "response", "tcp", "redirect"] repository = "https://github.com/hyperlane-dev/hyperlane.git" categories = ["network-programming", "web-programming"] -exclude = [ - "target", - "Cargo.lock", - "sh", - ".github", - "logs", - "**/*.log" -] +exclude = ["target", "Cargo.lock", "sh", ".github", "logs", "**/*.log"] [dependencies] -futures = "0.3.31" -hyperlane = "10.14.0" -hyperlane-time = "0.7.12" +rand = "0.10.0" +futures = "0.3.32" num_cpus = "1.17.0" once_cell = "1.21.3" -rand = "0.9.2" -serde = "1.0.228" -serde_json = "1.0.145" +hyperlane = "18.2.1" +serde_json = "1.0.149" +hyperlane-time = "0.7.22" +serde = { version = "1.0.228", features = ["derive"] } sqlx = { version = "0.8.6", features = ["runtime-tokio", "postgres"] } [profile.dev] incremental = false opt-level = 3 lto = true -panic = "unwind" +panic = "abort" debug = false codegen-units = 1 strip = "debuginfo" @@ -42,10 +35,12 @@ strip = "debuginfo" incremental = false opt-level = 3 lto = true -panic = "unwind" +panic = "abort" debug = false codegen-units = 1 strip = "debuginfo" +overflow-checks = false +rpath = false [features] dev = [] diff --git a/frameworks/Rust/hyperlane/README.md b/frameworks/Rust/hyperlane/README.md index 8afc763acc2..87f5fe6c4d6 100644 --- a/frameworks/Rust/hyperlane/README.md +++ b/frameworks/Rust/hyperlane/README.md @@ -1,39 +1,39 @@ -# [hyperlane](https://github.com/hyperlane-dev/hyperlane) web framework - -## Description - -> A lightweight, high-performance, and cross-platform Rust HTTP server library built on Tokio. It simplifies modern web service development by providing built-in support for middleware, WebSocket, Server-Sent Events (SSE), and raw TCP communication. With a unified and ergonomic API across Windows, Linux, and MacOS, it enables developers to build robust, scalable, and event-driven network applications with minimal overhead and maximum flexibility. - -## Database - -PostgreSQL. - -## Test URLs - -### Test 1: JSON Encoding - - http://localhost:8080/json - -### Test 2: Single Row Query - - http://localhost:8080/db - -### Test 3: Multi Row Query - - http://localhost:8080/query?q=20 - -### Test 4: Fortunes (Template rendering) - - http://localhost:8080/fortunes - -### Test 5: Update Query - - http://localhost:8080/upda?q=20 - -### Test 6: Plaintext - - http://localhost:8080/plaintext - -### Test 7: Caching - - http://localhost:8080/cached-quer?c=20 +# [hyperlane web framework](https://github.com/hyperlane-dev/hyperlane) + +## Description + +> A lightweight, high-performance, and cross-platform Rust HTTP server library built on Tokio. It simplifies modern web service development by providing built-in support for middleware, WebSocket, Server-Sent Events (SSE), and raw TCP communication. With a unified and ergonomic API across Windows, Linux, and MacOS, it enables developers to build robust, scalable, and event-driven network applications with minimal overhead and maximum flexibility. + +## Database + +PostgreSQL. + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:8080/json + +### Test 2: Single Row Query + + http://localhost:8080/db + +### Test 3: Multi Row Query + + http://localhost:8080/query?q=20 + +### Test 4: Fortunes (Template rendering) + + http://localhost:8080/fortunes + +### Test 5: Update Query + + http://localhost:8080/upda?q=20 + +### Test 6: Plaintext + + http://localhost:8080/plaintext + +### Test 7: Caching + + http://localhost:8080/cached-quer?c=20 diff --git a/frameworks/Rust/hyperlane/benchmark_config.json b/frameworks/Rust/hyperlane/benchmark_config.json index 5476d84b5dd..8ca664aa351 100644 --- a/frameworks/Rust/hyperlane/benchmark_config.json +++ b/frameworks/Rust/hyperlane/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "hyperlane", + "maintainers": ["eastspire"], "tests": [ { "default": { diff --git a/frameworks/Rust/hyperlane/hyperlane.default.dockerfile b/frameworks/Rust/hyperlane/hyperlane.default.dockerfile index 023ac9612cc..be6b4d2517f 100644 --- a/frameworks/Rust/hyperlane/hyperlane.default.dockerfile +++ b/frameworks/Rust/hyperlane/hyperlane.default.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.89 +FROM rust:1.93 RUN apt-get update -yqq && apt-get install -yqq cmake g++ binutils lld @@ -8,7 +8,7 @@ ADD ./ /hyperlane_techempower WORKDIR /hyperlane_techempower RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native -C link-arg=-fuse-ld=lld" cargo build --release +RUN cargo build --release EXPOSE 8080 diff --git a/frameworks/Rust/hyperlane/src/config/fn.rs b/frameworks/Rust/hyperlane/src/config/fn.rs new file mode 100644 index 00000000000..cbc24acd93e --- /dev/null +++ b/frameworks/Rust/hyperlane/src/config/fn.rs @@ -0,0 +1,13 @@ +use super::*; + +pub(crate) fn init_server_config() -> ServerConfig { + let mut server_config: ServerConfig = ServerConfig::default(); + server_config + .set_address(Server::format_bind_address(DEFAULT_HOST, 8080)) + .set_nodelay(Some(false)); + server_config +} + +pub(crate) fn init_request_config() -> RequestConfig { + RequestConfig::low_security() +} diff --git a/frameworks/Rust/hyperlane/src/config/mod.rs b/frameworks/Rust/hyperlane/src/config/mod.rs new file mode 100644 index 00000000000..910cac3089e --- /dev/null +++ b/frameworks/Rust/hyperlane/src/config/mod.rs @@ -0,0 +1,5 @@ +mod r#fn; + +pub(crate) use r#fn::*; + +use super::*; diff --git a/frameworks/Rust/hyperlane/src/db/fn.rs b/frameworks/Rust/hyperlane/src/db/fn.rs index ab7ea1dd86e..b3edc26c7ee 100644 --- a/frameworks/Rust/hyperlane/src/db/fn.rs +++ b/frameworks/Rust/hyperlane/src/db/fn.rs @@ -1,5 +1,6 @@ use super::*; +#[inline(always)] pub(crate) fn get_db_connection() -> &'static DbPoolConnection { &DB } diff --git a/frameworks/Rust/hyperlane/src/db/mod.rs b/frameworks/Rust/hyperlane/src/db/mod.rs index 7607362706f..49981db5f3d 100644 --- a/frameworks/Rust/hyperlane/src/db/mod.rs +++ b/frameworks/Rust/hyperlane/src/db/mod.rs @@ -1,9 +1,7 @@ -pub(crate) mod r#fn; -pub(crate) mod r#static; -pub(crate) mod r#type; +mod r#fn; +mod r#static; +mod r#type; -pub(crate) use r#fn::*; -pub(crate) use r#static::*; -pub(crate) use r#type::*; +pub(crate) use {r#fn::*, r#static::*, r#type::*}; use super::*; diff --git a/frameworks/Rust/hyperlane/src/main.rs b/frameworks/Rust/hyperlane/src/main.rs index 3e16079e292..4f15d37ae9c 100644 --- a/frameworks/Rust/hyperlane/src/main.rs +++ b/frameworks/Rust/hyperlane/src/main.rs @@ -1,52 +1,49 @@ -pub(crate) mod db; -pub(crate) mod middleware; -pub(crate) mod route; -pub(crate) mod server; -pub(crate) mod utils; - -pub(crate) use db::*; -pub(crate) use server::*; -pub(crate) use utils::*; - -pub(crate) use std::fmt; - -pub(crate) use futures::{executor::block_on, future::join_all}; -pub(crate) use hyperlane::{ - tokio::{spawn, task::JoinHandle}, - *, -}; -pub(crate) use hyperlane_time::*; -pub(crate) use once_cell::sync::Lazy; -pub(crate) use rand::{Rng, SeedableRng, rng, rngs::SmallRng}; -pub(crate) use serde::*; -pub(crate) use serde_json::{Value, json}; -pub(crate) use sqlx::{ - Pool, Postgres, Row, - postgres::{PgPoolOptions, PgRow}, - query as db_query, +mod config; +mod db; +mod middleware; +mod route; +mod server; +mod utils; + +use {config::*, db::*, middleware::*, route::*, server::*, utils::*}; + +use std::fmt; + +use { + futures::{executor::block_on, future::join_all}, + hyperlane::{ + tokio::{spawn, task::JoinHandle}, + *, + }, + hyperlane_time::*, + once_cell::sync::Lazy, + rand::{RngExt, SeedableRng, rng, rngs::SmallRng}, + serde::*, + serde_json::{Value, json}, + sqlx::{ + Pool, Postgres, Row, + postgres::{PgPoolOptions, PgRow}, + query as db_query, + }, }; -use middleware::*; -use route::*; - #[tokio::main] async fn main() { init_db().await; - - let config: ServerConfig = ServerConfig::new().await; - config.port(8080).await; - config.disable_nodelay().await; - - let server: Server = Server::from(config).await; - server.request_middleware::().await; - server.route::("/plaintext").await; - server.route::("/json").await; - server.route::("/cached-quer").await; - server.route::("/db").await; - server.route::("/query").await; - server.route::("/fortunes").await; - server.route::("/upda").await; - - let server_hook: ServerControlHook = server.run().await.unwrap(); - server_hook.wait().await; + Server::default() + .server_config(init_server_config()) + .request_config(init_request_config()) + .request_middleware::() + .route::("/plaintext") + .route::("/json") + .route::("/cached-quer") + .route::("/db") + .route::("/query") + .route::("/fortunes") + .route::("/upda") + .run() + .await + .unwrap() + .wait() + .await; } diff --git a/frameworks/Rust/hyperlane/src/middleware/impl.rs b/frameworks/Rust/hyperlane/src/middleware/impl.rs index f0559d8d539..410bede39a6 100644 --- a/frameworks/Rust/hyperlane/src/middleware/impl.rs +++ b/frameworks/Rust/hyperlane/src/middleware/impl.rs @@ -1,22 +1,17 @@ use super::*; impl ServerHook for RequestMiddleware { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { - ctx.set_response_version(HttpVersion::HTTP1_1) - .await - .set_response_header(CONNECTION, KEEP_ALIVE) - .await - .set_response_header(SERVER, HYPERLANE) - .await - .set_response_header(DATE, &gmt()) - .await - .set_response_status_code(200) - .await - .set_response_header(CONTENT_TYPE, APPLICATION_JSON) - .await; + async fn handle(self, ctx: &mut Context) { + ctx.get_mut_response() + .set_version(HttpVersion::Http1_1) + .set_header(CONNECTION, KEEP_ALIVE) + .set_header(SERVER, HYPERLANE) + .set_header(DATE, gmt()) + .set_status_code(200) + .set_header(CONTENT_TYPE, APPLICATION_JSON); } } diff --git a/frameworks/Rust/hyperlane/src/middleware/mod.rs b/frameworks/Rust/hyperlane/src/middleware/mod.rs index 976fe87bede..5a079a819ec 100644 --- a/frameworks/Rust/hyperlane/src/middleware/mod.rs +++ b/frameworks/Rust/hyperlane/src/middleware/mod.rs @@ -1,5 +1,5 @@ -pub(crate) mod r#impl; -pub(crate) mod r#struct; +mod r#impl; +mod r#struct; pub(crate) use r#struct::*; diff --git a/frameworks/Rust/hyperlane/src/middleware/struct.rs b/frameworks/Rust/hyperlane/src/middleware/struct.rs index dd36f832031..694ef4ed3f7 100644 --- a/frameworks/Rust/hyperlane/src/middleware/struct.rs +++ b/frameworks/Rust/hyperlane/src/middleware/struct.rs @@ -1 +1,2 @@ +#[derive(Clone, Copy, Default)] pub(crate) struct RequestMiddleware; diff --git a/frameworks/Rust/hyperlane/src/route/impl.rs b/frameworks/Rust/hyperlane/src/route/impl.rs index 96eb1080be9..2d8e128b2b7 100644 --- a/frameworks/Rust/hyperlane/src/route/impl.rs +++ b/frameworks/Rust/hyperlane/src/route/impl.rs @@ -1,111 +1,152 @@ use super::*; impl ServerHook for JsonRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { + async fn handle(self, ctx: &mut Context) { let json: Value = json!({ KEY_MESSAGE: RESPONSEDATA_STR }); - let run = || async { - ctx.set_response_body(&serde_json::to_vec(&json).unwrap_or_default()) - .await; - ctx.send().await.unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&json).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { + ctx.get_mut_response() + .set_body(serde_json::to_vec(&json).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } } - ctx.closed().await; } } impl ServerHook for PlaintextRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { - ctx.set_response_header(CONTENT_TYPE, TEXT_PLAIN).await; - ctx.set_response_body(&RESPONSEDATA_BIN).await; - let run = || async { - ctx.send().await.unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + async fn handle(self, ctx: &mut Context) { + ctx.get_mut_response() + .set_header(CONTENT_TYPE, TEXT_PLAIN) + .set_body(RESPONSEDATA_BIN); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + break; + } } - ctx.closed().await; + ctx.set_closed(true); } } impl ServerHook for DbRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { + async fn handle(self, ctx: &mut Context) { let db_connection: &DbPoolConnection = get_db_connection(); - let run = || async { + let query_row: QueryRow = random_world_row(db_connection).await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&query_row).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { let query_row: QueryRow = random_world_row(db_connection).await; - ctx.set_response_body(&serde_json::to_vec(&query_row).unwrap_or_default()) - .await - .send() - .await - .unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&query_row).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + break; + } } - ctx.closed().await; + ctx.set_closed(true); } } impl ServerHook for QueryRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { - let run = || async { + async fn handle(self, ctx: &mut Context) { + let queries: Queries = ctx + .get_request() + .try_get_query(QUERY_DB_QUERY_KEY) + .and_then(|queries| queries.parse::().ok()) + .unwrap_or_default() + .min(ROW_LIMIT as Queries) + .max(1); + let db_pool: &DbPoolConnection = get_db_connection(); + let data: Vec = get_some_row_id(queries, db_pool).await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&data).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { let queries: Queries = ctx - .try_get_request_query(QUERY_DB_QUERY_KEY) - .await + .get_request() + .try_get_query(QUERY_DB_QUERY_KEY) .and_then(|queries| queries.parse::().ok()) .unwrap_or_default() .min(ROW_LIMIT as Queries) .max(1); - let db_pool: &DbPoolConnection = get_db_connection(); let data: Vec = get_some_row_id(queries, db_pool).await; - ctx.set_response_body(&serde_json::to_vec(&data).unwrap_or_default()) - .await - .send() - .await - .unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&data).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + break; + } } - ctx.closed().await; + ctx.set_closed(true); } } impl ServerHook for FortunesRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { - ctx.set_response_header( + async fn handle(self, ctx: &mut Context) { + ctx.get_mut_response().set_header( CONTENT_TYPE, - &ContentType::format_content_type_with_charset(TEXT_HTML, UTF8), - ) - .await; - let run = || async { + ContentType::format_content_type_with_charset(TEXT_HTML, UTF8), + ); + let all_rows: Vec = all_world_row().await; + let mut fortunes_list: Vec = all_rows + .iter() + .map(|row| { + let id: i32 = row.get(KEY_ID); + Fortunes::new(id, row.get(KEY_MESSAGE)) + }) + .collect(); + fortunes_list.push(Fortunes::new( + 0, + "Additional fortune added at request time.".to_owned(), + )); + fortunes_list.sort_by(|it, next| it.message.cmp(&next.message)); + let res: String = FortunesTemplate::new(fortunes_list).to_string(); + ctx.get_mut_response().set_body(&res); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { let all_rows: Vec = all_world_row().await; let mut fortunes_list: Vec = all_rows .iter() @@ -120,70 +161,92 @@ impl ServerHook for FortunesRoute { )); fortunes_list.sort_by(|it, next| it.message.cmp(&next.message)); let res: String = FortunesTemplate::new(fortunes_list).to_string(); - ctx.set_response_body(&res).await.send().await.unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + ctx.get_mut_response().set_body(&res); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + break; + } } - ctx.closed().await; + ctx.set_closed(true); } } impl ServerHook for UpdateRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { - let run = || async { + async fn handle(self, ctx: &mut Context) { + let queries: Queries = ctx + .get_request() + .try_get_query(UPDATE_DB_QUERY_KEY) + .and_then(|queries| queries.parse::().ok()) + .unwrap_or_default() + .min(ROW_LIMIT as Queries) + .max(1); + let res: Vec = update_world_rows(queries).await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&res).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { let queries: Queries = ctx - .try_get_request_query(UPDATE_DB_QUERY_KEY) - .await + .get_request() + .try_get_query(UPDATE_DB_QUERY_KEY) .and_then(|queries| queries.parse::().ok()) .unwrap_or_default() .min(ROW_LIMIT as Queries) .max(1); let res: Vec = update_world_rows(queries).await; - ctx.set_response_body(&serde_json::to_vec(&res).unwrap_or_default()) - .await - .send() - .await - .unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&res).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + break; + } } - ctx.closed().await; + ctx.set_closed(true); } } impl ServerHook for CachedQueryRoute { - async fn new(_ctx: &Context) -> Self { + async fn new(_ctx: &mut Context) -> Self { Self } - async fn handle(self, ctx: &Context) { - let run = || async { + async fn handle(self, ctx: &mut Context) { + let count: Queries = ctx + .get_request() + .try_get_query(CACHE_QUERY_KEY) + .and_then(|queries| queries.parse::().ok()) + .unwrap_or_default() + .min(ROW_LIMIT as Queries) + .max(1); + let res: Vec<&QueryRow> = CACHE.iter().take(count as usize).collect(); + ctx.get_mut_response() + .set_body(serde_json::to_vec(&res).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + return; + } + while ctx.http_from_stream().await.is_ok() { let count: Queries = ctx - .try_get_request_query(CACHE_QUERY_KEY) - .await + .get_request() + .try_get_query(CACHE_QUERY_KEY) .and_then(|queries| queries.parse::().ok()) .unwrap_or_default() .min(ROW_LIMIT as Queries) .max(1); let res: Vec<&QueryRow> = CACHE.iter().take(count as usize).collect(); - ctx.set_response_body(&serde_json::to_vec(&res).unwrap_or_default()) - .await - .send() - .await - .unwrap(); - }; - run().await; - while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { - run().await; + ctx.get_mut_response() + .set_body(serde_json::to_vec(&res).unwrap_or_default()); + if ctx.try_send().await.is_err() { + ctx.set_closed(true); + break; + } } - ctx.closed().await; + ctx.set_closed(true); } } diff --git a/frameworks/Rust/hyperlane/src/route/mod.rs b/frameworks/Rust/hyperlane/src/route/mod.rs index 6d47ae6e8b4..5a079a819ec 100644 --- a/frameworks/Rust/hyperlane/src/route/mod.rs +++ b/frameworks/Rust/hyperlane/src/route/mod.rs @@ -1,8 +1,6 @@ -pub(crate) mod r#impl; -pub(crate) mod r#struct; +mod r#impl; +mod r#struct; pub(crate) use r#struct::*; use super::*; - -use sqlx::{Row, postgres::PgRow}; diff --git a/frameworks/Rust/hyperlane/src/route/struct.rs b/frameworks/Rust/hyperlane/src/route/struct.rs index 107268ec78a..4f9a873c448 100644 --- a/frameworks/Rust/hyperlane/src/route/struct.rs +++ b/frameworks/Rust/hyperlane/src/route/struct.rs @@ -1,7 +1,20 @@ +#[derive(Clone, Copy, Default)] pub(crate) struct JsonRoute; + +#[derive(Clone, Copy, Default)] pub(crate) struct PlaintextRoute; + +#[derive(Clone, Copy, Default)] pub(crate) struct DbRoute; + +#[derive(Clone, Copy, Default)] pub(crate) struct QueryRoute; + +#[derive(Clone, Copy, Default)] pub(crate) struct FortunesRoute; + +#[derive(Clone, Copy, Default)] pub(crate) struct UpdateRoute; + +#[derive(Clone, Copy, Default)] pub(crate) struct CachedQueryRoute; diff --git a/frameworks/Rust/hyperlane/src/server/const.rs b/frameworks/Rust/hyperlane/src/server/const.rs index c6c0cd98828..46dec4c7036 100644 --- a/frameworks/Rust/hyperlane/src/server/const.rs +++ b/frameworks/Rust/hyperlane/src/server/const.rs @@ -15,7 +15,6 @@ pub(crate) const KEY_ID: &str = "id"; pub(crate) const KEY_RANDOM_NUMBER: &str = "randomnumber"; pub(crate) const KEY_MESSAGE: &str = "message"; pub(crate) const DB_MAX_CONNECTIONS: u32 = 100; -pub(crate) const HTTP_BUFFER: usize = 256; pub(crate) const QUERY_DB_QUERY_KEY: &str = "q"; pub(crate) const UPDATE_DB_QUERY_KEY: &str = "q"; pub(crate) const CACHE_QUERY_KEY: &str = "c"; diff --git a/frameworks/Rust/hyperlane/src/server/impl.rs b/frameworks/Rust/hyperlane/src/server/impl.rs index ee8045d2dff..e373617d937 100644 --- a/frameworks/Rust/hyperlane/src/server/impl.rs +++ b/frameworks/Rust/hyperlane/src/server/impl.rs @@ -1,6 +1,7 @@ use super::*; impl QueryRow { + #[inline(always)] pub fn new(id: Queries, random_number: Queries) -> Self { Self { id, @@ -10,12 +11,14 @@ impl QueryRow { } impl Fortunes { + #[inline(always)] pub fn new(id: Queries, message: String) -> Self { Self { id, message } } } impl FortunesTemplate { + #[inline(always)] pub fn new(list: Vec) -> Self { Self(list) } @@ -23,12 +26,11 @@ impl FortunesTemplate { impl fmt::Display for FortunesTemplate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let fortunes: &Vec = &self.0; let _ = write!( f, "Fortunes" ); - for tem in fortunes.iter() { + for tem in self.0.iter() { let row: String = format!( "", tem.id, diff --git a/frameworks/Rust/hyperlane/src/server/mod.rs b/frameworks/Rust/hyperlane/src/server/mod.rs index d806bc43dc2..4701af3d708 100644 --- a/frameworks/Rust/hyperlane/src/server/mod.rs +++ b/frameworks/Rust/hyperlane/src/server/mod.rs @@ -1,10 +1,8 @@ -pub(crate) mod r#const; -pub(crate) mod r#impl; -pub(crate) mod r#struct; -pub(crate) mod r#type; +mod r#const; +mod r#impl; +mod r#struct; +mod r#type; -pub(crate) use r#const::*; -pub(crate) use r#struct::*; -pub(crate) use r#type::*; +pub(crate) use {r#const::*, r#struct::*, r#type::*}; use super::*; diff --git a/frameworks/Rust/hyperlane/src/server/struct.rs b/frameworks/Rust/hyperlane/src/server/struct.rs index 779f5dd691f..b0be42c62fe 100644 --- a/frameworks/Rust/hyperlane/src/server/struct.rs +++ b/frameworks/Rust/hyperlane/src/server/struct.rs @@ -1,17 +1,17 @@ use super::*; #[allow(bad_style)] -#[derive(Serialize, Default, Clone)] +#[derive(Clone, Copy, Default, Serialize)] pub(crate) struct QueryRow { pub(crate) id: Queries, pub(crate) randomNumber: Queries, } -#[derive(Serialize)] +#[derive(Clone, Default, Serialize)] pub(crate) struct Fortunes { pub(crate) id: Queries, pub(crate) message: String, } -#[derive(Serialize)] +#[derive(Clone, Default, Serialize)] pub(crate) struct FortunesTemplate(pub(crate) Vec); diff --git a/frameworks/Rust/hyperlane/src/utils/fn.rs b/frameworks/Rust/hyperlane/src/utils/fn.rs index bd29a75f21f..50e7a1f66a4 100644 --- a/frameworks/Rust/hyperlane/src/utils/fn.rs +++ b/frameworks/Rust/hyperlane/src/utils/fn.rs @@ -1,5 +1,6 @@ use super::*; +#[inline(always)] pub(crate) fn get_thread_count() -> usize { num_cpus::get().max(1) } diff --git a/frameworks/Rust/ignitia/Cargo.lock b/frameworks/Rust/ignitia/Cargo.lock index 229c20bd620..15d63edbd49 100644 --- a/frameworks/Rust/ignitia/Cargo.lock +++ b/frameworks/Rust/ignitia/Cargo.lock @@ -242,9 +242,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" @@ -1560,9 +1560,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-traits" @@ -2364,30 +2364,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", diff --git a/frameworks/Rust/khttp/README.md b/frameworks/Rust/khttp/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/khttp/benchmark_config.json b/frameworks/Rust/khttp/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/nickel/Cargo.toml b/frameworks/Rust/nickel/Cargo.toml deleted file mode 100644 index 1a8353f3b82..00000000000 --- a/frameworks/Rust/nickel/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "nickel" -version = "0.0.2" -edition = "2018" - -[dependencies] -serde = "1.0" -serde_json = "1.0" -serde_derive = "1.0" -nickel = "0.10.0" -nickel_macros = "0.1.0" diff --git a/frameworks/Rust/nickel/benchmark_config.json b/frameworks/Rust/nickel/benchmark_config.json deleted file mode 100644 index 4e527ab0bae..00000000000 --- a/frameworks/Rust/nickel/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "nickel", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "nickel", - "language": "Rust", - "orm": "raw", - "platform": "Rust", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "nickel", - "notes": "", - "versus": "", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Rust/nickel/config.toml b/frameworks/Rust/nickel/config.toml deleted file mode 100644 index 0101a0383eb..00000000000 --- a/frameworks/Rust/nickel/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "nickel" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "raw" -platform = "Rust" -webserver = "hyper" -versus = "" diff --git a/frameworks/Rust/nickel/nickel.dockerfile b/frameworks/Rust/nickel/nickel.dockerfile deleted file mode 100644 index 028a640cd50..00000000000 --- a/frameworks/Rust/nickel/nickel.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.44 - -ADD ./ /nickel -WORKDIR /nickel - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release - -EXPOSE 8080 - -CMD ./target/release/nickel diff --git a/frameworks/Rust/nickel/src/main.rs b/frameworks/Rust/nickel/src/main.rs deleted file mode 100644 index eea5095da68..00000000000 --- a/frameworks/Rust/nickel/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -#[macro_use] -extern crate nickel; -extern crate serde; -extern crate serde_json; -#[macro_use] -extern crate serde_derive; - -use nickel::{HttpRouter, MediaType, Nickel}; - -#[derive(Serialize, Deserialize)] -struct Message { - message: String, -} - -fn main() { - let mut server = Nickel::new(); - let mut router = Nickel::router(); - - router.get( - "/json", - middleware! { |_, mut response| - response.set(MediaType::Json); - let message: Message = Message{ - message: "Hello, World!".to_string(), - }; - serde_json::to_string(&message).unwrap() - }, - ); - - router.get( - "/plaintext", - middleware! { |_, mut response| - response.set(MediaType::Txt); - "Hello, World!" - }, - ); - - server.utilize(router); - server.listen("0.0.0.0:8080").unwrap(); -} diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml old mode 100755 new mode 100644 index ae3e4cc977b..f8235905d35 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ntex-bench" +name = "ntex-framework" version = "3.0.0" edition = "2018" @@ -60,17 +60,17 @@ tokio = ["ntex/tokio"] # compio runtime compio = ["ntex/compio"] -# neon runtime -neon = ["ntex/neon"] +# neon polling runtime +neon = ["ntex/neon-polling"] -# neon runtime +# neon io-uring runtime neon-uring = ["ntex/neon-uring"] [dependencies] -ntex = "3.0.0-pre.5" -ntex-neon = "0.1.35" -ntex-net = "3.0.0" -ntex-bytes = { version = "1", features=["simd"] } +ntex = "3.4.0" +ntex-io = "3.9" +ntex-service = "4.5" +ntex-bytes = { version = "1.5", features=["simd"] } mimalloc = { version = "0.1.25", default-features = false } snmalloc-rs = { version = "0.3.3", features = ["native-cpu"] } yarte = { version = "0.15", features = ["bytes-buf", "json"] } diff --git a/frameworks/Rust/ntex/benchmark_config.json b/frameworks/Rust/ntex/benchmark_config.json old mode 100755 new mode 100644 index 16615823f11..6be357246af --- a/frameworks/Rust/ntex/benchmark_config.json +++ b/frameworks/Rust/ntex/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "ntex", + "maintainers": ["fafhrd91"], "tests": [{ "default": { "json_url": "/json", @@ -119,7 +120,7 @@ "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "ntex", @@ -137,7 +138,7 @@ "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "ntex", @@ -155,7 +156,7 @@ "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, - "approach": "Realistic", + "approach": "Stripped", "classification": "Platform", "database": "Postgres", "framework": "ntex", diff --git a/frameworks/Rust/ntex/ntex-compio.dockerfile b/frameworks/Rust/ntex/ntex-compio.dockerfile index c825e18078e..e19a11de235 100644 --- a/frameworks/Rust/ntex/ntex-compio.dockerfile +++ b/frameworks/Rust/ntex/ntex-compio.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-db-compio.dockerfile b/frameworks/Rust/ntex/ntex-db-compio.dockerfile index c892bcdc9fc..5494356b9ec 100644 --- a/frameworks/Rust/ntex/ntex-db-compio.dockerfile +++ b/frameworks/Rust/ntex/ntex-db-compio.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile b/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile index 2b65aaa1556..ac26af3b416 100644 --- a/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile +++ b/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-db-neon.dockerfile b/frameworks/Rust/ntex/ntex-db-neon.dockerfile index 0bd30d7d49c..22473e13511 100644 --- a/frameworks/Rust/ntex/ntex-db-neon.dockerfile +++ b/frameworks/Rust/ntex/ntex-db-neon.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-db.dockerfile b/frameworks/Rust/ntex/ntex-db.dockerfile index 3a890860fd7..a8daed7423d 100644 --- a/frameworks/Rust/ntex/ntex-db.dockerfile +++ b/frameworks/Rust/ntex/ntex-db.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-neon-uring.dockerfile b/frameworks/Rust/ntex/ntex-neon-uring.dockerfile index f69e45e7f8d..eb0a700207d 100644 --- a/frameworks/Rust/ntex/ntex-neon-uring.dockerfile +++ b/frameworks/Rust/ntex/ntex-neon-uring.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-neon.dockerfile b/frameworks/Rust/ntex/ntex-neon.dockerfile index 91b0ac1acba..0b5500c1b93 100644 --- a/frameworks/Rust/ntex/ntex-neon.dockerfile +++ b/frameworks/Rust/ntex/ntex-neon.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-plt-compio.dockerfile b/frameworks/Rust/ntex/ntex-plt-compio.dockerfile index 849e224994b..1515b3348c3 100644 --- a/frameworks/Rust/ntex/ntex-plt-compio.dockerfile +++ b/frameworks/Rust/ntex/ntex-plt-compio.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile b/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile index 943c6ef2373..7a29258b91b 100644 --- a/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile +++ b/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-plt-neon.dockerfile b/frameworks/Rust/ntex/ntex-plt-neon.dockerfile index 766886f6997..572316818e0 100644 --- a/frameworks/Rust/ntex/ntex-plt-neon.dockerfile +++ b/frameworks/Rust/ntex/ntex-plt-neon.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex-plt.dockerfile b/frameworks/Rust/ntex/ntex-plt.dockerfile index a0009eb72d1..23c8a225568 100644 --- a/frameworks/Rust/ntex/ntex-plt.dockerfile +++ b/frameworks/Rust/ntex/ntex-plt.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/ntex.dockerfile b/frameworks/Rust/ntex/ntex.dockerfile index 0104d032595..123bbbefa43 100644 --- a/frameworks/Rust/ntex/ntex.dockerfile +++ b/frameworks/Rust/ntex/ntex.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.93 # Disable simd at jsonescape # ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index dc2eb93ffe3..e2ee3860cbb 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -1,7 +1,5 @@ -use std::{borrow::Cow, cell::RefCell}; - use nanorand::{Rng, WyRand}; -use ntex::util::{Bytes, BytesMut}; +use ntex::util::Bytes; use smallvec::SmallVec; use tokio_postgres::{connect, Client, Statement}; use yarte::TemplateBytesTrait; @@ -15,26 +13,24 @@ pub struct World { } #[derive(Debug, sonic_rs::Serialize)] -pub struct Fortune { +pub struct Fortune<'a> { pub id: i32, - pub message: Cow<'static, str>, + pub message: &'a str, } #[derive(yarte::TemplateBytes)] #[template(path = "fortune.hbs")] -pub struct FortunesTemplate<'a> { - pub fortunes: &'a Vec, +pub struct FortunesTemplate<'a, 'b> { + pub fortunes: &'a [Fortune<'b>], } /// Postgres interface pub struct PgConnection { cl: Client, + rng: WyRand, fortune: Statement, world: Statement, - rng: WyRand, updates: Statement, - buf: RefCell, - fbuf: RefCell>, } impl PgConnection { @@ -52,12 +48,10 @@ impl PgConnection { PgConnection { cl, - fortune, world, updates, + fortune, rng: WyRand::new(), - buf: RefCell::new(BytesMut::with_capacity(10 * 1024 * 1024)), - fbuf: RefCell::new(Vec::with_capacity(64)), } } } @@ -65,20 +59,19 @@ impl PgConnection { impl PgConnection { pub async fn get_world(&self) -> Bytes { let random_id = (self.rng.clone().generate::() % 10_000 + 1) as i32; - let row = self.cl.query_one(&self.world, &[&random_id]).await.unwrap(); - let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 1024); - sonic_rs::to_writer( - utils::BytesWriter(&mut body), - &World { - id: row.get(0), - randomnumber: row.get(1), - }, - ) - .unwrap(); - body.split().freeze() + utils::buffer(256, |body| { + sonic_rs::to_writer( + utils::BVecWriter(body), + &World { + id: row.get(0), + randomnumber: row.get(1), + }, + ) + .unwrap(); + body.take() + }) } pub async fn get_worlds(&self, num: usize) -> Bytes { @@ -98,10 +91,10 @@ impl PgConnection { }) } - let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 2 * 1024); - sonic_rs::to_writer(utils::BytesWriter(&mut body), &worlds[..]).unwrap(); - body.split().freeze() + utils::buffer(2 * 1024, |body| { + sonic_rs::to_writer(utils::BVecWriter(body), &worlds[..]).unwrap(); + body.take() + }) } pub async fn update(&self, num: usize) -> Bytes { @@ -125,43 +118,40 @@ impl PgConnection { }); queries.push(self.cl.query_one(&self.world, &[&ids[idx]])); }); - let _ = self - .cl - .query(&self.updates, &[&ids, &numbers]) - .await - .unwrap(); + let update = self.cl.query(&self.updates, &[&ids, &numbers]); - let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body, 2 * 1024); - sonic_rs::to_writer(utils::BytesWriter(&mut body), &worlds[..]).unwrap(); - body.split().freeze() + for query in queries { + let _rand: i32 = query.await.unwrap().get(1); + } + update.await.unwrap(); + + utils::buffer(2 * 1024, |body| { + sonic_rs::to_writer(utils::BVecWriter(body), &worlds[..]).unwrap(); + body.take() + }) } pub async fn tell_fortune(&self) -> Bytes { let rows = self.cl.query_raw(&self.fortune, &[]).await.unwrap(); - let mut fortunes = self.fbuf.borrow_mut(); + let mut fortunes = Vec::with_capacity(16); fortunes.push(Fortune { id: 0, - message: Cow::Borrowed("Additional fortune added at request time."), + message: "Additional fortune added at request time.", }); fortunes.extend(rows.iter().map(|row| Fortune { id: row.get(0), - message: Cow::Owned(row.get(1)), + message: row.get(1), })); fortunes.sort_by(|it, next| it.message.cmp(&next.message)); - let mut body = std::mem::replace(&mut *self.buf.borrow_mut(), BytesMut::new()); - utils::reserve(&mut body, 4 * 1024); - - FortunesTemplate { - fortunes: &fortunes, - } - .write_call(&mut body); - fortunes.clear(); + utils::buffer(4 * 1024, |body| { + FortunesTemplate { + fortunes: &fortunes, + } + .write_call(body); - let result = body.split().freeze(); - let _ = std::mem::replace(&mut *self.buf.borrow_mut(), body); - result + body.take() + }) } } diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index 23494837277..d9e094338df 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/frameworks/Rust/ntex/src/main.rs @@ -2,7 +2,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; -use ntex::{http, util::BytesMut, web}; +use ntex::{http, web}; use sonic_rs::Serialize; mod utils; @@ -14,14 +14,17 @@ pub struct Message { #[web::get("/json")] async fn json() -> web::HttpResponse { - let mut body = BytesMut::with_capacity(utils::SIZE); - sonic_rs::to_writer( - utils::BytesWriter(&mut body), - &Message { - message: "Hello, World!", - }, - ) - .unwrap(); + let body = utils::buffer(256, |buf| { + sonic_rs::to_writer( + utils::BVecWriter(buf), + &Message { + message: "Hello, World!", + }, + ) + .unwrap(); + + buf.take() + }); let mut response = web::HttpResponse::with_body(http::StatusCode::OK, body.into()); response.headers_mut().insert(SERVER, utils::HDR_SERVER); diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index 83619c5053c..69185f031e4 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/frameworks/Rust/ntex/src/main_plt.rs @@ -3,7 +3,8 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use std::{future::Future, io, pin::Pin, task::ready, task::Context, task::Poll}; -use ntex::{fn_service, http::h1, io::Io, io::RecvError}; +use ntex::io::{Io, IoConfig, RecvError}; +use ntex::{fn_service, http::h1, http::DateService}; use sonic_rs::Serialize; mod utils; @@ -35,32 +36,30 @@ impl Future for App { match ready!(this.io.poll_recv(&this.codec, cx)) { Ok((req, _)) => { let _ = this.io.with_write_buf(|buf| { - buf.with_bytes_mut(|buf| { - utils::reserve(buf, 2 * 1024); - match req.path() { - "/json" => { - buf.extend_from_slice(JSON); - this.codec.set_date_header(buf); + this.io.cfg().write_buf().resize(buf); + match req.path() { + "/json" => { + buf.extend_from_slice(JSON); + DateService.bset_date_header(buf); - sonic_rs::to_writer( - utils::BytesWriter(buf), - &Message { - message: "Hello, World!", - }, - ) - .unwrap(); - } - "/plaintext" => { - buf.extend_from_slice(PLAIN); - this.codec.set_date_header(buf); - buf.extend_from_slice(BODY); - } - _ => { - buf.extend_from_slice(HTTPNFOUND); - buf.extend_from_slice(HDR_SERVER); - } + sonic_rs::to_writer( + utils::BVecWriter(buf), + &Message { + message: "Hello, World!", + }, + ) + .unwrap(); } - }) + "/plaintext" => { + buf.extend_from_slice(PLAIN); + DateService.bset_date_header(buf); + buf.extend_from_slice(BODY); + } + _ => { + buf.extend_from_slice(HTTPNFOUND); + buf.extend_from_slice(HDR_SERVER); + } + } }); } Err(RecvError::WriteBackpressure) => { @@ -85,7 +84,7 @@ async fn main() -> io::Result<()> { .bind("tfb", "0.0.0.0:8080", async |_| { fn_service(|io| App { io, - codec: h1::Codec::default(), + codec: h1::Codec::new(0, true, utils::config().get::()), }) })? .config("tfb", utils::config()) diff --git a/frameworks/Rust/ntex/src/utils.rs b/frameworks/Rust/ntex/src/utils.rs index b3399bd8497..7c071dee8e3 100644 --- a/frameworks/Rust/ntex/src/utils.rs +++ b/frameworks/Rust/ntex/src/utils.rs @@ -1,9 +1,10 @@ #![allow(dead_code)] -use std::{cmp, io, io::Write, mem::MaybeUninit, slice::from_raw_parts_mut}; +use std::{cell::Cell, cmp, io, io::Write, mem::MaybeUninit, slice::from_raw_parts_mut}; use atoi::FromRadix10; use ntex::http::{header::HeaderValue, HttpServiceConfig, KeepAlive}; -use ntex::{io::IoConfig, time::Seconds, util::BufMut, util::Bytes, util::BytesMut, SharedCfg}; +use ntex::util::{BufMut, Bytes, BytesMut}; +use ntex::{io::IoConfig, time::Seconds, SharedCfg}; use sonic_rs::writer::WriteExt; pub const HDR_SERVER: HeaderValue = HeaderValue::from_static("N"); @@ -14,7 +15,7 @@ pub const HDR_HTML_CONTENT_TYPE: HeaderValue = pub const BODY_PLAIN_TEXT: Bytes = Bytes::from_static(b"Hello, World!"); const HW: usize = 128 * 1024; -pub const SIZE: usize = 27; +pub const SIZE: usize = 23; pub fn config() -> SharedCfg { thread_local! { @@ -32,7 +33,7 @@ pub fn config() -> SharedCfg { .set_payload_read_rate(Seconds::ZERO, Seconds::ZERO, 0), ).into(); } - CFG.with(|cfg| *cfg) + CFG.with(Clone::clone) } pub fn db_config() -> SharedCfg { @@ -44,7 +45,7 @@ pub fn db_config() -> SharedCfg { .set_write_buf(65535, 2048, 128), ).into() } - CFG.with(|cfg| *cfg) + CFG.with(Clone::clone) } pub fn get_query_param(query: Option<&str>) -> usize { @@ -57,16 +58,29 @@ pub fn get_query_param(query: Option<&str>) -> usize { cmp::min(500, cmp::max(1, q) as usize) } -pub fn reserve(buf: &mut BytesMut, lw: usize) { - let remaining = buf.remaining_mut(); - if remaining < lw { - buf.reserve(HW); +pub fn buffer(lw: usize, f: F) -> R +where + F: FnOnce(&mut BytesMut) -> R, +{ + thread_local! { + static BUF: Cell> = Cell::new(Some(BytesMut::new())); } + BUF.with(|buf| { + let mut b = buf.take().unwrap(); + let remaining = b.remaining_mut(); + if remaining < lw { + b.reserve_capacity(HW); + } + + let result = f(&mut b); + buf.set(Some(b)); + result + }) } -pub struct BytesWriter<'a>(pub &'a mut BytesMut); +pub struct BVecWriter<'a>(pub &'a mut BytesMut); -impl Write for BytesWriter<'_> { +impl Write for BVecWriter<'_> { fn write(&mut self, src: &[u8]) -> Result { self.0.extend_from_slice(src); Ok(src.len()) @@ -77,7 +91,7 @@ impl Write for BytesWriter<'_> { } } -impl WriteExt for BytesWriter<'_> { +impl WriteExt for BVecWriter<'_> { #[inline(always)] fn reserve_with(&mut self, additional: usize) -> Result<&mut [MaybeUninit], io::Error> { self.0.reserve(additional); diff --git a/frameworks/Rust/ohkami/Cargo.lock b/frameworks/Rust/ohkami/Cargo.lock deleted file mode 100644 index 4760079eca4..00000000000 --- a/frameworks/Rust/ohkami/Cargo.lock +++ /dev/null @@ -1,2519 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "annotate-snippets" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" -dependencies = [ - "unicode-width", - "yansi-term", -] - -[[package]] -name = "anysc-rustls" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b04ec47ea6da4486baee0d3d4b18fb4b8c89d777f1005d5235c4caf164fa6d1" -dependencies = [ - "futures-rustls", - "tokio-rustls", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue 2.5.0", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue 2.5.0", - "fastrand 2.3.0", - "futures-lite 2.6.1", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" -dependencies = [ - "async-lock", - "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "async-io" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue 2.5.0", - "futures-io", - "futures-lite 2.6.1", - "parking", - "polling", - "rustix 1.0.8", - "slab", - "windows-sys 0.60.2", -] - -[[package]] -name = "async-lock" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "async-process" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite 2.6.1", - "rustix 1.0.8", -] - -[[package]] -name = "async-signal" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 1.0.8", - "signal-hook-registry", - "slab", - "windows-sys 0.60.2", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-lc-rs" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" -dependencies = [ - "bindgen", - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease 0.2.37", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.106", - "which", -] - -[[package]] -name = "bitflags" -version = "2.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" - -[[package]] -name = "bitmaps" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite 2.6.1", - "piper", -] - -[[package]] -name = "buddy-alloc" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3240a4cb09cf0da6a51641bd40ce90e96ea6065e3a1adc46434029254bcc2d09" - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "byte_reader" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cache-padded" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" - -[[package]] -name = "cc" -version = "1.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "ctrlc" -version = "3.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" -dependencies = [ - "nix 0.30.1", - "windows-sys 0.59.0", -] - -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.106", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "enclose" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eef75b364b1baff88ff28dc34e4c7c0ebd138abd76f4e58e24e37d9b7f54b8f1" - -[[package]] -name = "errno" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue 2.5.0", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "futures-core", - "futures-sink", - "nanorand", - "pin-project", - "spin", -] - -[[package]] -name = "framework_benchmarks" -version = "0.24.0" -dependencies = [ - "futures-util", - "ohkami", - "rand 0.8.5", - "tokio", - "tokio-postgres", - "yarte", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand 2.3.0", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "futures-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" -dependencies = [ - "futures-io", - "rustls", - "rustls-pki-types", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.3+wasi-0.2.4", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "glommio" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8bc1fce949d18098dc0a4e861314e40351a0144ebf61e59bdb5254a2273b2" -dependencies = [ - "ahash", - "backtrace", - "bitflags", - "bitmaps", - "buddy-alloc", - "cc", - "concurrent-queue 1.2.4", - "crossbeam", - "enclose", - "flume", - "futures-lite 1.13.0", - "intrusive-collections", - "lazy_static", - "libc", - "lockfree", - "log", - "nix 0.27.1", - "pin-project-lite", - "rlimit", - "scoped-tls", - "scopeguard", - "signal-hook", - "sketches-ddsketch", - "smallvec", - "socket2 0.4.10", - "tracing", - "typenum", -] - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "intrusive-collections" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" -dependencies = [ - "memoffset", -] - -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.175" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" - -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets 0.53.3", -] - -[[package]] -name = "libredox" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" -dependencies = [ - "bitflags", - "libc", - "redox_syscall", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "lockfree" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ee94b5ad113c7cb98c5a040f783d0952ee4fe100993881d1673c2cb002dd23" -dependencies = [ - "owned-alloc", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mews" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8554a5554e9be00776567382b100a89e550a6031fc76356455157d230caca7a5" -dependencies = [ - "base64", - "futures-util", - "glommio", - "nio", - "sha1", - "smol", - "tokio", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "mpmc-channel" -version = "0.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9184bf37b24a7fcdc91a9ca61efc4f3510276693f4693735556a77cc42cc342c" - -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "nio" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c8716fafb666bc4100593e8dcbbf930480692f9cd7755b21279343ff52b8db" -dependencies = [ - "crossbeam-channel", - "futures", - "libc", - "mio", - "mpmc-channel", - "nio-macros", - "socket2 0.5.10", - "tokio", -] - -[[package]] -name = "nio-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a67f7f91ca31eaa3fa95a2654d86f34ea912e3b0fec9f4a89e0890b64a4e33e" -dependencies = [ - "quote2", - "syn 2.0.106", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "ohkami" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a18bebc444bf9ed43b2ae864b111da831d584fa46e88aa9fa26b72d3afaf4a" -dependencies = [ - "anysc-rustls", - "base64", - "byte_reader", - "ctrlc", - "futures-util", - "glommio", - "hmac", - "mews", - "mime_guess", - "nio", - "num_cpus", - "ohkami_lib", - "ohkami_macros", - "serde", - "serde_json", - "sha2", - "smol", - "tokio", - "uuid", -] - -[[package]] -name = "ohkami_lib" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057e4f200cc0d0cc66a28d55fe371acc5a7c02f66ef13c0b41a84c8ff88d1025" -dependencies = [ - "byte_reader", - "percent-encoding", - "serde", -] - -[[package]] -name = "ohkami_macros" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15df818179dd272de9c427c08b3d5eaf7511cfdf41e63b232ce99723d603be0c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "owned-alloc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6" - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - -[[package]] -name = "polling" -version = "3.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" -dependencies = [ - "cfg-if", - "concurrent-queue 2.5.0", - "hermit-abi", - "pin-project-lite", - "rustix 1.0.8", - "windows-sys 0.60.2", -] - -[[package]] -name = "postgres-protocol" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" -dependencies = [ - "base64", - "byteorder", - "bytes", - "fallible-iterator", - "hmac", - "md-5", - "memchr", - "rand 0.9.2", - "sha2", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" -dependencies = [ - "bytes", - "fallible-iterator", - "postgres-protocol", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.106", -] - -[[package]] -name = "proc-macro2" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "quote2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61aa775e928368b9a33bcac44f47f4132f30b0b6a17eb15c0873fc8af899211" -dependencies = [ - "proc-macro2", - "quote", - "quote2-macros", -] - -[[package]] -name = "quote2-macros" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ceeba20cfeffd4e0f7dd03ef72e55d115be2927b97424249a02fed0e86647a" - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] - -[[package]] -name = "redox_syscall" -version = "0.5.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rlimit" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0bf25554376fd362f54332b8410a625c71f15445bca32ffdfdf4ec9ac91726" -dependencies = [ - "libc", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", -] - -[[package]] -name = "rustls" -version = "0.23.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" -dependencies = [ - "aws-lc-rs", - "log", - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "serde_json" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" -dependencies = [ - "libc", -] - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "sketches-ddsketch" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d2ecae5fcf33b122e2e6bd520a57ccf152d2dde3b38c71039df1a6867264ee" - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "smol" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" -dependencies = [ - "async-channel", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-net", - "async-process", - "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.47.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "pin-project-lite", - "slab", - "socket2 0.6.0", - "windows-sys 0.59.0", -] - -[[package]] -name = "tokio-postgres" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "rand 0.9.2", - "socket2 0.5.10", - "tokio", - "tokio-util", - "whoami", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "uuid" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "v_eval" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9" -dependencies = [ - "regex", - "syn 1.0.109", -] - -[[package]] -name = "v_htmlescape" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasi" -version = "0.14.3+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - -[[package]] -name = "whoami" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.3", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "wit-bindgen" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" - -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] - -[[package]] -name = "yarte" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfce1df93f3b16e5272221a559e60bbbaaa71dbc042a43996d223e51a690aab2" -dependencies = [ - "yarte_derive", - "yarte_helpers", -] - -[[package]] -name = "yarte_codegen" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a79312078b97a195de91a8c1457c2e0d7abd97e6e605f3cdeb01b3c105d2cff" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "yarte_helpers", - "yarte_hir", -] - -[[package]] -name = "yarte_derive" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b296edd7e1a81717b6f794baa2de8dfe89646050847161550b2d963b3ca6fe80" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "yarte_codegen", - "yarte_helpers", - "yarte_hir", - "yarte_parser", -] - -[[package]] -name = "yarte_helpers" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d1076f8cee9541ea5ffbecd9102f751252c91f085e7d30a18a3ce805ebd3ee" -dependencies = [ - "dtoa", - "itoa", - "prettyplease 0.1.25", - "serde", - "syn 1.0.109", - "toml", - "v_htmlescape", -] - -[[package]] -name = "yarte_hir" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee42d2f704a3b1d8bc111d47a705d1302a0943d85e4c230f4e8300ee0dde4a6" -dependencies = [ - "derive_more", - "proc-macro2", - "quote", - "syn 1.0.109", - "v_eval", - "v_htmlescape", - "yarte_helpers", - "yarte_parser", -] - -[[package]] -name = "yarte_parser" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538f72049cf7104e12d5c444048d112cb8fc788a31308afd912442a381ba860c" -dependencies = [ - "annotate-snippets", - "derive_more", - "proc-macro2", - "quote", - "serde", - "syn 1.0.109", - "unicode-xid", - "yarte_helpers", -] - -[[package]] -name = "zerocopy" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/frameworks/Rust/ohkami/Cargo.toml b/frameworks/Rust/ohkami/Cargo.toml index c905f405235..39b06b6b9ba 100644 --- a/frameworks/Rust/ohkami/Cargo.toml +++ b/frameworks/Rust/ohkami/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "framework_benchmarks" -version = "0.24.0" +version = "0.24.5" edition = "2024" -authors = ["kanarus "] +authors = ["kanarus "] [dependencies] ohkami = { version = "0.24" } -tokio = { optional = true, version = "1.47", features = ["rt"] } +tokio = { optional = true, version = "1.49", features = ["rt"] } tokio-postgres = { optional = true, version = "0.7" } yarte = { optional = true, version = "0.15" } futures-util = { optional = true, version = "0.3" } -rand = { optional = true, version = "0.8", features = ["small_rng"] } +rand = { optional = true, version = "0.10" } [features] rt_tokio = ["ohkami/rt_tokio", "tokio", "tokio-postgres", "yarte", "futures-util", "rand"] diff --git a/frameworks/Rust/ohkami/benchmark_config.json b/frameworks/Rust/ohkami/benchmark_config.json index ce44db39c24..690675f905c 100644 --- a/frameworks/Rust/ohkami/benchmark_config.json +++ b/frameworks/Rust/ohkami/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "ohkami", + "maintainers": ["kanarus"], "tests": [ { "default": { diff --git a/frameworks/Rust/ohkami/rt_glommio.dockerfile b/frameworks/Rust/ohkami/rt_glommio.dockerfile index d8426468dec..2c08258447f 100644 --- a/frameworks/Rust/ohkami/rt_glommio.dockerfile +++ b/frameworks/Rust/ohkami/rt_glommio.dockerfile @@ -1,23 +1,20 @@ -FROM rust:1.89-slim-bookworm AS builder +FROM rust:1.93-slim-trixie AS builder RUN apt update && apt install -y --no-install-recommends \ pkg-config \ git \ && rm -rf /var/lib/apt/lists/* -COPY ./Cargo.toml /build/ -COPY ./src/ /build/src/ -COPY ./rt_glommio/ /build/rt_glommio/ - WORKDIR /build/rt_glommio +COPY ./Cargo.toml /build/ +COPY ./src/ /build/src/ +COPY ./rt_glommio/ /build/rt_glommio/ ENV RUSTFLAGS="-C target-cpu=native" RUN cargo build --release ########################################################## FROM gcr.io/distroless/cc-debian12 - COPY --from=builder /build/rt_glommio/target/release/framework_benchmarks-glommio /app/ - EXPOSE 8000 CMD [ "/app/framework_benchmarks-glommio" ] diff --git a/frameworks/Rust/ohkami/rt_glommio/Cargo.lock b/frameworks/Rust/ohkami/rt_glommio/Cargo.lock index 0ef27d22413..bbac2f4c2a9 100644 --- a/frameworks/Rust/ohkami/rt_glommio/Cargo.lock +++ b/frameworks/Rust/ohkami/rt_glommio/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -23,22 +23,54 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.17", "once_cell", "version_check", ] +[[package]] +name = "anysc-rustls" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d010c908adfa812166d183ebb0b4541611c344b4942609cd67e3739f1b8063aa" +dependencies = [ + "futures-rustls", + "tokio-rustls", +] + [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -46,7 +78,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-link", ] [[package]] @@ -57,9 +89,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitmaps" @@ -76,6 +108,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "buddy-alloc" version = "0.4.2" @@ -84,9 +125,9 @@ checksum = "3240a4cb09cf0da6a51641bd40ce90e96ea6065e3a1adc46434029254bcc2d09" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "byte_reader" @@ -102,18 +143,21 @@ checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" [[package]] name = "cc" -version = "1.2.10" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -121,6 +165,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + [[package]] name = "concurrent-queue" version = "1.2.4" @@ -154,9 +207,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -197,9 +250,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -207,12 +260,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ - "nix 0.29.0", - "windows-sys", + "dispatch2", + "nix 0.31.1", + "windows-sys 0.61.2", ] [[package]] @@ -226,11 +280,39 @@ dependencies = [ "subtle", ] +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "enclose" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef4f6f904480430009ad8f22edc9573e26e4f137365f014d7ea998d5341639a" +checksum = "eef75b364b1baff88ff28dc34e4c7c0ebd138abd76f4e58e24e37d9b7f54b8f1" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] [[package]] name = "fastrand" @@ -241,6 +323,12 @@ dependencies = [ "instant", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "flume" version = "0.10.14" @@ -256,7 +344,7 @@ dependencies = [ [[package]] name = "framework_benchmarks" -version = "0.21.0" +version = "0.24.0" dependencies = [ "ohkami", ] @@ -270,17 +358,23 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -297,30 +391,40 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -336,9 +440,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -347,11 +451,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glommio" @@ -390,9 +506,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hmac" @@ -423,15 +539,25 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -445,17 +571,16 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -470,15 +595,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.25" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -491,21 +616,37 @@ dependencies = [ [[package]] name = "mews" -version = "0.2.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21788e6e675e8f19754e8c520ed420977ebade2867e2ff8363357b68c2ef8e8a" +checksum = "d26d2eb1dd3a8a9f12854e2c587932304ee2ec1293325262005faecb843de000" dependencies = [ "base64", "futures-util", - "glommio", "sha1", + "tokio", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", ] [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -516,7 +657,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "getrandom", + "getrandom 0.2.17", ] [[package]] @@ -533,9 +674,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" dependencies = [ "bitflags", "cfg-if", @@ -545,29 +686,45 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "ohkami" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37844b8da12eece89bd239e4d8cb7d7dad07978f6f20b3917d6fe7c289361f58" +checksum = "89179e5b7b78273d97fbe8f7764df196cfaa1a9746e03a4add2fd3bc2260c1d2" dependencies = [ + "anysc-rustls", "base64", "byte_reader", "ctrlc", @@ -575,19 +732,20 @@ dependencies = [ "glommio", "hmac", "mews", - "num_cpus", + "mime_guess", "ohkami_lib", "ohkami_macros", "serde", "serde_json", "sha2", + "uuid", ] [[package]] name = "ohkami_lib" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e95fa8274aba0c04904453fdd847898faf86856f7e80180305a51a5636338ed8" +checksum = "33aef8eb8e08d32935a58ff4c1a70816100a9c6fdbc48d52af42f8570dca623a" dependencies = [ "byte_reader", "percent-encoding", @@ -596,9 +754,9 @@ dependencies = [ [[package]] name = "ohkami_macros" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f326ade375c9f24daa9c029f2f6019bff9157bb780239839a6e4ce9aa136178f" +checksum = "99b3a535998f2bddbb6edfcdcc4b029944baa1704db4e5ba12eff5bc9f34700e" dependencies = [ "proc-macro2", "quote", @@ -607,9 +765,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "owned-alloc" @@ -625,24 +783,24 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", @@ -655,30 +813,44 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rlimit" version = "0.6.2" @@ -690,15 +862,51 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "scoped-tls" @@ -714,18 +922,28 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -734,14 +952,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -757,9 +976,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -774,9 +993,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -784,10 +1003,11 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -799,18 +1019,15 @@ checksum = "04d2ecae5fcf33b122e2e6bd520a57ccf152d2dde3b38c71039df1a6867264ee" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" @@ -839,20 +1056,39 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -861,9 +1097,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -872,24 +1108,46 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.15" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uuid" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "version_check" @@ -905,40 +1163,37 @@ checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen" -version = "0.2.100" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" +name = "wasm-bindgen" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -946,22 +1201,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] @@ -988,15 +1243,30 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1060,3 +1330,21 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/frameworks/Rust/ohkami/rt_glommio/Cargo.toml b/frameworks/Rust/ohkami/rt_glommio/Cargo.toml index 78bc03f50b8..5160995565e 100644 --- a/frameworks/Rust/ohkami/rt_glommio/Cargo.toml +++ b/frameworks/Rust/ohkami/rt_glommio/Cargo.toml @@ -2,7 +2,7 @@ name = "framework_benchmarks-glommio" version = "0.0.0" edition = "2024" -authors = ["kanarus "] +authors = ["kanarus "] [profile.release] lto = true diff --git a/frameworks/Rust/ohkami/rt_nio.dockerfile b/frameworks/Rust/ohkami/rt_nio.dockerfile index af664d37c84..dba10428893 100644 --- a/frameworks/Rust/ohkami/rt_nio.dockerfile +++ b/frameworks/Rust/ohkami/rt_nio.dockerfile @@ -1,22 +1,19 @@ -FROM rust:1.89-slim-bookworm AS builder +FROM rust:1.93-slim-trixie AS builder RUN apt update && apt install -y --no-install-recommends \ pkg-config \ && rm -rf /var/lib/apt/lists/* +WORKDIR /build/rt_nio COPY ./Cargo.toml /build/ COPY ./src/ /build/src/ -COPY ./rt_nio/ /build/rt_nio/ - -WORKDIR /build/rt_nio +COPY ./rt_nio/ /build/rt_nio/ ENV RUSTFLAGS="-C target-cpu=native" RUN cargo build --release ########################################################## FROM gcr.io/distroless/cc-debian12 - COPY --from=builder /build/rt_nio/target/release/framework_benchmarks-nio /app/ - EXPOSE 8000 CMD [ "/app/framework_benchmarks-nio" ] diff --git a/frameworks/Rust/ohkami/rt_nio/Cargo.lock b/frameworks/Rust/ohkami/rt_nio/Cargo.lock index 0ffab198e12..85aef9a499c 100644 --- a/frameworks/Rust/ohkami/rt_nio/Cargo.lock +++ b/frameworks/Rust/ohkami/rt_nio/Cargo.lock @@ -3,39 +3,35 @@ version = 4 [[package]] -name = "addr2line" -version = "0.24.2" +name = "anysc-rustls" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "d010c908adfa812166d183ebb0b4541611c344b4942609cd67e3739f1b8063aa" dependencies = [ - "gimli", + "futures-rustls", + "tokio-rustls", ] [[package]] -name = "adler2" -version = "2.0.0" +name = "aws-lc-rs" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +dependencies = [ + "aws-lc-sys", + "zeroize", +] [[package]] -name = "backtrace" -version = "0.3.74" +name = "aws-lc-sys" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", + "cc", + "cmake", + "dunce", + "fs_extra", ] [[package]] @@ -46,9 +42,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -59,6 +55,21 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + [[package]] name = "byte_reader" version = "3.1.1" @@ -67,15 +78,27 @@ checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" [[package]] name = "bytes" -version = "1.9.0" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -83,6 +106,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -93,10 +125,10 @@ dependencies = [ ] [[package]] -name = "crossbeam-channel" -version = "0.5.14" +name = "crossbeam-queue" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] @@ -109,9 +141,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -119,12 +151,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ + "dispatch2", "nix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -139,106 +172,88 @@ dependencies = [ ] [[package]] -name = "framework_benchmarks" -version = "0.21.0" +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "ohkami", + "bitflags", + "block2", + "libc", + "objc2", ] [[package]] -name = "framework_benchmarks-nio" -version = "0.0.0" -dependencies = [ - "framework_benchmarks", - "nio", -] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] -name = "futures" -version = "0.3.31" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "framework_benchmarks" +version = "0.24.0" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "ohkami", ] [[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +name = "framework_benchmarks-nio" +version = "0.0.0" dependencies = [ - "futures-core", - "futures-sink", + "framework_benchmarks", + "nio", ] [[package]] -name = "futures-core" -version = "0.3.31" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] -name = "futures-executor" -version = "0.3.31" +name = "futures-core" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] -name = "futures-macro" -version = "0.3.31" +name = "futures-rustls" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "futures-io", + "rustls", + "rustls-pki-types", ] -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -253,10 +268,27 @@ dependencies = [ ] [[package]] -name = "gimli" -version = "0.31.1" +name = "getrandom" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] [[package]] name = "hmac" @@ -269,69 +301,86 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "libc" -version = "0.2.169" +name = "jobserver" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] [[package]] -name = "lock_api" -version = "0.4.12" +name = "js-sys" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ - "autocfg", - "scopeguard", + "once_cell", + "wasm-bindgen", ] +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + [[package]] name = "log" -version = "0.4.25" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mews" -version = "0.2.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21788e6e675e8f19754e8c520ed420977ebade2867e2ff8363357b68c2ef8e8a" +checksum = "d26d2eb1dd3a8a9f12854e2c587932304ee2ec1293325262005faecb843de000" dependencies = [ "base64", - "nio", + "futures-util", "sha1", "tokio", ] [[package]] -name = "miniz_oxide" -version = "0.8.3" +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ - "adler2", + "mime", + "unicase", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -342,35 +391,64 @@ checksum = "9184bf37b24a7fcdc91a9ca61efc4f3510276693f4693735556a77cc42cc342c" [[package]] name = "nio" -version = "0.0.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af5df74a05351a6e56595f76330c6dc0641452291d69f36e7541a949bbbc93eb" +checksum = "4880ec39f35a6b0af2a011146105035a1c5a85c264e4b138a02f380a210956d6" dependencies = [ - "crossbeam-channel", - "futures", - "libc", + "crossbeam-queue", + "crossbeam-utils", + "futures-io", "mio", - "mpmc-channel", + "nio-future", "nio-macros", - "socket2", + "nio-metrics", + "nio-task", + "nio-threadpool", "tokio", ] +[[package]] +name = "nio-future" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e26fd19409f5b9d577e2f2b2f968815518dbe87f013512502726331e461fe9" + [[package]] name = "nio-macros" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a67f7f91ca31eaa3fa95a2654d86f34ea912e3b0fec9f4a89e0890b64a4e33e" +checksum = "dc6e97e541224aaea6062d926943eacf9b37b0f15728a79e454d78f06ad5a699" dependencies = [ "quote2", "syn", ] +[[package]] +name = "nio-metrics" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b847afb78d305b5e7db9bffb5e8d2d306cba627cadcf12d370dab5724b7e00f1" + +[[package]] +name = "nio-task" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb099fa8a20f2e9e741b7337ce5a2699269acaa3b7be4ab77018877ca11a75a" + +[[package]] +name = "nio-threadpool" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa124711c2d3e36ee2165d6e15c96a5249f2158e7effe6e2baa965a016d302b" +dependencies = [ + "mpmc-channel", +] + [[package]] name = "nix" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" dependencies = [ "bitflags", "cfg-if", @@ -379,25 +457,33 @@ dependencies = [ ] [[package]] -name = "object" -version = "0.36.7" +name = "objc2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ - "memchr", + "objc2-encode", ] +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + [[package]] name = "ohkami" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37844b8da12eece89bd239e4d8cb7d7dad07978f6f20b3917d6fe7c289361f58" +checksum = "89179e5b7b78273d97fbe8f7764df196cfaa1a9746e03a4add2fd3bc2260c1d2" dependencies = [ + "anysc-rustls", "base64", "byte_reader", "ctrlc", "hmac", "mews", + "mime_guess", "nio", "ohkami_lib", "ohkami_macros", @@ -405,13 +491,14 @@ dependencies = [ "serde_json", "sha2", "tokio", + "uuid", ] [[package]] name = "ohkami_lib" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e95fa8274aba0c04904453fdd847898faf86856f7e80180305a51a5636338ed8" +checksum = "33aef8eb8e08d32935a58ff4c1a70816100a9c6fdbc48d52af42f8570dca623a" dependencies = [ "byte_reader", "percent-encoding", @@ -420,9 +507,9 @@ dependencies = [ [[package]] name = "ohkami_macros" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f326ade375c9f24daa9c029f2f6019bff9157bb780239839a6e4ce9aa136178f" +checksum = "99b3a535998f2bddbb6edfcdcc4b029944baa1704db4e5ba12eff5bc9f34700e" dependencies = [ "proc-macro2", "quote", @@ -430,33 +517,16 @@ dependencies = [ ] [[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" +name = "once_cell" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" @@ -464,26 +534,20 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -506,46 +570,91 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6ceeba20cfeffd4e0f7dd03ef72e55d115be2927b97424249a02fed0e86647a" [[package]] -name = "redox_syscall" -version = "0.5.8" +name = "r-efi" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ - "bitflags", + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", ] [[package]] -name = "rustc-demangle" -version = "0.1.24" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustls-webpki" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -554,14 +663,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -577,9 +687,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -587,38 +697,16 @@ dependencies = [ ] [[package]] -name = "signal-hook-registry" -version = "1.4.2" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.8" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "subtle" @@ -628,9 +716,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -639,44 +727,57 @@ dependencies = [ [[package]] name = "tokio" -version = "1.43.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "libc", - "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", ] [[package]] -name = "tokio-macros" -version = "2.5.0" +name = "tokio-rustls" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "proc-macro2", - "quote", - "syn", + "rustls", + "tokio", ] [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.15" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uuid" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "version_check" @@ -686,9 +787,69 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -701,11 +862,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets", + "windows-link", ] [[package]] @@ -771,3 +932,21 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/frameworks/Rust/ohkami/rt_nio/Cargo.toml b/frameworks/Rust/ohkami/rt_nio/Cargo.toml index a159e3e829f..25999a0215e 100644 --- a/frameworks/Rust/ohkami/rt_nio/Cargo.toml +++ b/frameworks/Rust/ohkami/rt_nio/Cargo.toml @@ -2,7 +2,7 @@ name = "framework_benchmarks-nio" version = "0.0.0" edition = "2024" -authors = ["kanarus "] +authors = ["kanarus "] [profile.release] lto = true @@ -11,4 +11,4 @@ codegen-units = 1 [dependencies] framework_benchmarks = { path = "..", features = ["rt_nio"] } -nio = { version = "0.0" } +nio = { version = "0.1" } diff --git a/frameworks/Rust/ohkami/rt_smol.dockerfile b/frameworks/Rust/ohkami/rt_smol.dockerfile index 935e4d09f93..e44fa77fab8 100644 --- a/frameworks/Rust/ohkami/rt_smol.dockerfile +++ b/frameworks/Rust/ohkami/rt_smol.dockerfile @@ -1,22 +1,19 @@ -FROM rust:1.89-slim-bookworm AS builder +FROM rust:1.93-slim-trixie AS builder RUN apt update && apt install -y --no-install-recommends \ pkg-config \ && rm -rf /var/lib/apt/lists/* +WORKDIR /build/rt_smol COPY ./Cargo.toml /build/ COPY ./src/ /build/src/ -COPY ./rt_smol/ /build/rt_smol/ - -WORKDIR /build/rt_smol +COPY ./rt_smol/ /build/rt_smol/ ENV RUSTFLAGS="-C target-cpu=native" RUN cargo build --release ########################################################## FROM gcr.io/distroless/cc-debian12 - COPY --from=builder /build/rt_smol/target/release/framework_benchmarks-smol /app/ - EXPOSE 8000 CMD [ "/app/framework_benchmarks-smol" ] diff --git a/frameworks/Rust/ohkami/rt_smol/Cargo.lock b/frameworks/Rust/ohkami/rt_smol/Cargo.lock index 59625d44ce8..82e817004c2 100644 --- a/frameworks/Rust/ohkami/rt_smol/Cargo.lock +++ b/frameworks/Rust/ohkami/rt_smol/Cargo.lock @@ -2,11 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anysc-rustls" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d010c908adfa812166d183ebb0b4541611c344b4942609cd67e3739f1b8063aa" +dependencies = [ + "futures-rustls", + "tokio-rustls", +] + [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -16,22 +26,23 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", + "pin-project-lite", "slab", ] [[package]] name = "async-fs" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" dependencies = [ "async-lock", "blocking", @@ -40,11 +51,11 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", @@ -53,15 +64,14 @@ dependencies = [ "polling", "rustix", "slab", - "tracing", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", "event-listener-strategy", @@ -81,9 +91,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", "async-io", @@ -95,14 +105,13 @@ dependencies = [ "event-listener", "futures-lite", "rustix", - "tracing", ] [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -113,7 +122,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -130,9 +139,31 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] [[package]] name = "base64" @@ -142,9 +173,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -155,11 +186,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ "async-channel", "async-task", @@ -168,17 +208,35 @@ dependencies = [ "piper", ] +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + [[package]] name = "byte_reader" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -186,6 +244,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -212,9 +279,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -222,12 +289,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ + "dispatch2", "nix", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -241,21 +309,39 @@ dependencies = [ "subtle", ] +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -264,9 +350,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ "event-listener", "pin-project-lite", @@ -278,9 +364,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "framework_benchmarks" -version = "0.21.0" +version = "0.24.0" dependencies = [ "ohkami", ] @@ -293,23 +385,29 @@ dependencies = [ "smol", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -318,24 +416,34 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -349,11 +457,34 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hmac" @@ -366,44 +497,87 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] [[package]] name = "libc" -version = "0.2.169" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mews" -version = "0.2.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21788e6e675e8f19754e8c520ed420977ebade2867e2ff8363357b68c2ef8e8a" +checksum = "d26d2eb1dd3a8a9f12854e2c587932304ee2ec1293325262005faecb843de000" dependencies = [ "base64", + "futures-util", "sha1", - "smol", + "tokio", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", ] [[package]] name = "nix" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" dependencies = [ "bitflags", "cfg-if", @@ -411,31 +585,49 @@ dependencies = [ "libc", ] +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + [[package]] name = "ohkami" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37844b8da12eece89bd239e4d8cb7d7dad07978f6f20b3917d6fe7c289361f58" +checksum = "89179e5b7b78273d97fbe8f7764df196cfaa1a9746e03a4add2fd3bc2260c1d2" dependencies = [ + "anysc-rustls", "base64", "byte_reader", "ctrlc", "futures-util", "hmac", "mews", + "mime_guess", "ohkami_lib", "ohkami_macros", "serde", "serde_json", "sha2", "smol", + "uuid", ] [[package]] name = "ohkami_lib" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e95fa8274aba0c04904453fdd847898faf86856f7e80180305a51a5636338ed8" +checksum = "33aef8eb8e08d32935a58ff4c1a70816100a9c6fdbc48d52af42f8570dca623a" dependencies = [ "byte_reader", "percent-encoding", @@ -444,15 +636,21 @@ dependencies = [ [[package]] name = "ohkami_macros" -version = "0.21.0" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f326ade375c9f24daa9c029f2f6019bff9157bb780239839a6e4ce9aa136178f" +checksum = "99b3a535998f2bddbb6edfcdcc4b029944baa1704db4e5ba12eff5bc9f34700e" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "parking" version = "2.2.1" @@ -461,9 +659,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" @@ -471,12 +669,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "piper" version = "0.2.4" @@ -490,70 +682,135 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix", - "tracing", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", ] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustls-webpki" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -562,14 +819,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -585,32 +843,36 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smol" @@ -637,9 +899,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -647,32 +909,57 @@ dependencies = [ ] [[package]] -name = "tracing" -version = "0.1.41" +name = "tokio" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "pin-project-lite", - "tracing-core", ] [[package]] -name = "tracing-core" -version = "0.1.33" +name = "tokio-rustls" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.15" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uuid" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "version_check" @@ -680,15 +967,90 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -752,3 +1114,21 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/frameworks/Rust/ohkami/rt_smol/Cargo.toml b/frameworks/Rust/ohkami/rt_smol/Cargo.toml index 2484a598d18..ac9f5bf780c 100644 --- a/frameworks/Rust/ohkami/rt_smol/Cargo.toml +++ b/frameworks/Rust/ohkami/rt_smol/Cargo.toml @@ -2,7 +2,7 @@ name = "framework_benchmarks-smol" version = "0.0.0" edition = "2024" -authors = ["kanarus "] +authors = ["kanarus "] [profile.release] lto = true diff --git a/frameworks/Rust/ohkami/rt_tokio.dockerfile b/frameworks/Rust/ohkami/rt_tokio.dockerfile index 35359c9a9bf..67323354e34 100644 --- a/frameworks/Rust/ohkami/rt_tokio.dockerfile +++ b/frameworks/Rust/ohkami/rt_tokio.dockerfile @@ -1,26 +1,23 @@ -FROM rust:1.89-slim-bookworm AS builder +FROM rust:1.93-slim-trixie AS builder RUN apt update && apt install -y --no-install-recommends \ pkg-config \ - libpq-dev libssl-dev \ + libssl-dev \ && rm -rf /var/lib/apt/lists/* +WORKDIR /build/rt_tokio COPY ./Cargo.toml /build/ COPY ./src/ /build/src/ COPY ./rt_tokio/ /build/rt_tokio/ - -WORKDIR /build/rt_tokio ENV RUSTFLAGS="-C target-cpu=native" RUN cargo build --release ########################################################## FROM gcr.io/distroless/cc-debian12 - -COPY --from=builder /build/rt_tokio/target/release/framework_benchmarks-tokio /app/ - -EXPOSE 8000 ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world ENV MAX_CONNECTIONS=56 ENV MIN_CONNECTIONS=56 +COPY --from=builder /build/rt_tokio/target/release/framework_benchmarks-tokio /app/ +EXPOSE 8000 CMD [ "/app/framework_benchmarks-tokio" ] diff --git a/frameworks/Rust/ohkami/rt_tokio/Cargo.lock b/frameworks/Rust/ohkami/rt_tokio/Cargo.lock index 4a5fe5e8bf6..bfd9b33798d 100644 --- a/frameworks/Rust/ohkami/rt_tokio/Cargo.lock +++ b/frameworks/Rust/ohkami/rt_tokio/Cargo.lock @@ -2,26 +2,11 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -36,11 +21,17 @@ dependencies = [ "yansi-term", ] +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + [[package]] name = "anysc-rustls" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b04ec47ea6da4486baee0d3d4b18fb4b8c89d777f1005d5235c4caf164fa6d1" +checksum = "d010c908adfa812166d183ebb0b4541611c344b4942609cd67e3739f1b8063aa" dependencies = [ "futures-rustls", "tokio-rustls", @@ -54,20 +45,14 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" dependencies = [ "aws-lc-sys", "zeroize", @@ -75,66 +60,27 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" dependencies = [ - "bindgen", "cc", "cmake", "dunce", "fs_extra", ] -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease 0.2.37", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.106", - "which", -] - [[package]] name = "bitflags" -version = "2.8.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -145,11 +91,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "byte_reader" @@ -165,35 +120,27 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.10" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -202,21 +149,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "clang-sys" -version = "1.8.1" +name = "chacha20" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ - "glob", - "libc", - "libloading", + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.0", ] [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] @@ -236,11 +183,20 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -248,25 +204,26 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ + "dispatch2", "nix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -280,11 +237,23 @@ dependencies = [ "subtle", ] +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] + [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" [[package]] name = "dunce" @@ -293,19 +262,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] -name = "either" -version = "1.13.0" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -314,13 +283,25 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "framework_benchmarks" version = "0.24.0" dependencies = [ "futures-util", "ohkami", - "rand 0.8.5", + "rand 0.10.0", "tokio", "tokio-postgres", "yarte", @@ -331,7 +312,6 @@ name = "framework_benchmarks-tokio" version = "0.0.0" dependencies = [ "framework_benchmarks", - "num_cpus", "tokio", ] @@ -343,9 +323,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -353,25 +333,25 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -387,28 +367,27 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-macro", "futures-sink", "futures-task", "pin-project-lite", - "pin-utils", "slab", ] @@ -424,44 +403,61 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasip2", ] [[package]] -name = "gimli" -version = "0.31.1" +name = "getrandom" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.0", + "wasip2", + "wasip3", +] [[package]] -name = "glob" -version = "0.3.3" +name = "hashbrown" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] [[package]] -name = "hermit-abi" -version = "0.5.2" +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hmac" @@ -473,39 +469,28 @@ dependencies = [ ] [[package]] -name = "home" -version = "0.5.11" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] -name = "io-uring" -version = "0.7.10" +name = "indexmap" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jobserver" @@ -513,69 +498,56 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] -name = "libloading" -version = "0.8.8" +name = "libredox" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "cfg-if", - "windows-targets", + "bitflags", + "libc", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.25" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "md-5" @@ -589,15 +561,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mews" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8554a5554e9be00776567382b100a89e550a6031fc76356455157d230caca7a5" +checksum = "d26d2eb1dd3a8a9f12854e2c587932304ee2ec1293325262005faecb843de000" dependencies = [ "base64", "futures-util", @@ -621,37 +593,22 @@ dependencies = [ "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", ] [[package]] name = "nix" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" dependencies = [ "bitflags", "cfg-if", @@ -660,39 +617,25 @@ dependencies = [ ] [[package]] -name = "nom" -version = "7.1.3" +name = "objc2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ - "memchr", - "minimal-lexical", + "objc2-encode", ] [[package]] -name = "num_cpus" -version = "1.17.0" +name = "objc2-encode" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "ohkami" -version = "0.24.1" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a18bebc444bf9ed43b2ae864b111da831d584fa46e88aa9fa26b72d3afaf4a" +checksum = "89179e5b7b78273d97fbe8f7764df196cfaa1a9746e03a4add2fd3bc2260c1d2" dependencies = [ "anysc-rustls", "base64", @@ -712,9 +655,9 @@ dependencies = [ [[package]] name = "ohkami_lib" -version = "0.24.1" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057e4f200cc0d0cc66a28d55fe371acc5a7c02f66ef13c0b41a84c8ff88d1025" +checksum = "33aef8eb8e08d32935a58ff4c1a70816100a9c6fdbc48d52af42f8570dca623a" dependencies = [ "byte_reader", "percent-encoding", @@ -723,26 +666,26 @@ dependencies = [ [[package]] name = "ohkami_macros" -version = "0.24.1" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15df818179dd272de9c427c08b3d5eaf7511cfdf41e63b232ce99723d603be0c" +checksum = "99b3a535998f2bddbb6edfcdcc4b029944baa1704db4e5ba12eff5bc9f34700e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -750,37 +693,38 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-link", ] [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_shared", + "serde", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -791,17 +735,11 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[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.8" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +checksum = "3ee9dd5fe15055d2b6806f4736aa0c9637217074e224bbec46d4041b91bb9491" dependencies = [ "base64", "byteorder", @@ -817,9 +755,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +checksum = "54b858f82211e84682fecd373f68e1ceae642d8d751a1ebd13f33de6257b3e20" dependencies = [ "bytes", "fallible-iterator", @@ -828,9 +766,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] @@ -852,23 +790,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -879,35 +817,25 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_chacha", + "rand_core 0.9.5", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rand" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "chacha20", + "getrandom 0.4.1", + "rand_core 0.10.0", ] [[package]] @@ -917,41 +845,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.4", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -961,9 +886,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -972,9 +897,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "ring" @@ -984,24 +909,12 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc_version" version = "0.4.1" @@ -1011,24 +924,11 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "aws-lc-rs", "log", @@ -1041,18 +941,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "aws-lc-rs", "ring", @@ -1066,12 +966,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - [[package]] name = "scopeguard" version = "1.2.0" @@ -1080,40 +974,51 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -1123,18 +1028,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -1146,52 +1051,40 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.8" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1224,9 +1117,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -1235,9 +1128,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -1250,40 +1143,37 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "tokio-postgres" -version = "0.7.13" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" +checksum = "dcea47c8f71744367793f16c2db1f11cb859d28f436bdb4ca9193eb1f787ee42" dependencies = [ "async-trait", "byteorder", @@ -1299,7 +1189,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand 0.9.2", - "socket2 0.5.8", + "socket2", "tokio", "tokio-util", "whoami", @@ -1307,9 +1197,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -1317,9 +1207,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -1339,15 +1229,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-bidi" @@ -1357,24 +1247,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.15" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-width" @@ -1396,9 +1286,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "uuid" -version = "1.18.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1428,56 +1318,64 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.3+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasite" -version = "0.1.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1485,55 +1383,77 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.116", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] -name = "web-sys" -version = "0.3.77" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ - "js-sys", - "wasm-bindgen", + "leb128fmt", + "wasmparser", ] [[package]] -name = "which" -version = "4.4.2" +name = "wasm-metadata" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ - "either", - "home", - "once_cell", - "rustix", + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", ] [[package]] name = "whoami" -version = "1.5.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +checksum = "8fae98cf96deed1b7572272dfc777713c249ae40aa1cf8862e091e8b745f5361" dependencies = [ - "redox_syscall", + "libredox", "wasite", "web-sys", ] @@ -1560,22 +1480,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets", + "windows-link", ] [[package]] @@ -1584,14 +1519,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -1600,53 +1552,183 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease 0.2.37", + "syn 2.0.116", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease 0.2.37", + "proc-macro2", + "quote", + "syn 2.0.116", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "yansi-term" @@ -1744,27 +1826,32 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/frameworks/Rust/ohkami/rt_tokio/Cargo.toml b/frameworks/Rust/ohkami/rt_tokio/Cargo.toml index 8f464cad8b9..e993f2313be 100644 --- a/frameworks/Rust/ohkami/rt_tokio/Cargo.toml +++ b/frameworks/Rust/ohkami/rt_tokio/Cargo.toml @@ -2,7 +2,7 @@ name = "framework_benchmarks-tokio" version = "0.0.0" edition = "2024" -authors = ["kanarus "] +authors = ["kanarus "] [profile.release] lto = true @@ -12,4 +12,3 @@ codegen-units = 1 [dependencies] framework_benchmarks = { path = "..", features = ["rt_tokio"] } tokio = { version = "1.47", features = ["full"] } -num_cpus = { version = "1.17" } diff --git a/frameworks/Rust/ohkami/rt_tokio/src/main.rs b/frameworks/Rust/ohkami/rt_tokio/src/main.rs index 8a801fa838e..d39577987d3 100644 --- a/frameworks/Rust/ohkami/rt_tokio/src/main.rs +++ b/frameworks/Rust/ohkami/rt_tokio/src/main.rs @@ -22,7 +22,7 @@ async fn serve( } fn main() { - for _ in 0..(num_cpus::get() - 1/*for main thread*/) { + for _ in 0..(std::thread::available_parallelism().unwrap().get() - 1/*for main thread*/) { std::thread::spawn(|| { runtime().block_on(async { serve(|listener| async { diff --git a/frameworks/Rust/ohkami/src/errors.rs b/frameworks/Rust/ohkami/src/errors.rs new file mode 100644 index 00000000000..f2abefdf7e4 --- /dev/null +++ b/frameworks/Rust/ohkami/src/errors.rs @@ -0,0 +1,25 @@ +#![cfg(feature = "rt_tokio")] + +pub enum AppError { + Db(tokio_postgres::Error), +} + +impl From for AppError { + fn from(e: tokio_postgres::Error) -> Self { + Self::Db(e) + } +} + +impl ohkami::IntoResponse for AppError { + fn into_response(self) -> ohkami::Response { + match self { + Self::Db(_e) => { + #[cfg(debug_assertions)] + { + eprintln!("{_e:?}"); + } + ohkami::Response::InternalServerError() + } + } + } +} diff --git a/frameworks/Rust/ohkami/src/lib.rs b/frameworks/Rust/ohkami/src/lib.rs index aa289a822d5..867ea62bcaf 100644 --- a/frameworks/Rust/ohkami/src/lib.rs +++ b/frameworks/Rust/ohkami/src/lib.rs @@ -1,5 +1,6 @@ mod fangs; mod models; +#[cfg(feature = "rt_tokio")] mod errors; #[cfg(feature = "rt_tokio")] mod postgres; #[cfg(feature = "rt_tokio")] mod templates; @@ -9,6 +10,7 @@ use { ohkami::prelude::*, }; #[cfg(feature = "rt_tokio")] use { + errors::AppError, models::{Fortune, World, WorldsMeta}, postgres::Postgres, templates::FortunesTemplate, @@ -19,7 +21,6 @@ pub async fn ohkami() -> Ohkami { SetServer, #[cfg(feature = "rt_tokio")] Context::new(Postgres::new().await), - "/plaintext".GET(plaintext), "/json".GET(json_serialization), #[cfg(feature = "rt_tokio")] @@ -46,40 +47,40 @@ async fn json_serialization() -> Json { #[cfg(feature = "rt_tokio")] async fn single_database_query( Context(db): Context<'_, Postgres>, -) -> Json { - let world = db.select_random_world().await; - Json(world) +) -> Result, AppError> { + let world = db.select_random_world().await?; + Ok(Json(world)) } #[cfg(feature = "rt_tokio")] async fn multiple_database_query( Query(q): Query>, Context(db): Context<'_, Postgres>, -) -> Json> { +) -> Result>, AppError> { let n = q.parse(); - let worlds = db.select_n_random_worlds(n).await; - Json(worlds) + let worlds = db.select_n_random_worlds(n).await?; + Ok(Json(worlds)) } #[cfg(feature = "rt_tokio")] async fn fortunes( Context(db): Context<'_, Postgres>, -) -> FortunesTemplate { - let mut fortunes = db.select_all_fortunes().await; +) -> Result { + let mut fortunes = db.select_all_fortunes().await?; fortunes.push(Fortune { id: 0, message: String::from("Additional fortune added at request time."), }); fortunes.sort_unstable_by(|a, b| str::cmp(&a.message, &b.message)); - FortunesTemplate { fortunes } + Ok(FortunesTemplate { fortunes }) } #[cfg(feature = "rt_tokio")] async fn database_updates( Query(q): Query>, Context(db): Context<'_, Postgres>, -) -> Json> { +) -> Result>, AppError> { let n = q.parse(); - let worlds = db.update_randomnumbers_of_n_worlds(n).await; - Json(worlds) + let worlds = db.update_randomnumbers_of_n_worlds(n).await?; + Ok(Json(worlds)) } diff --git a/frameworks/Rust/ohkami/src/postgres.rs b/frameworks/Rust/ohkami/src/postgres.rs index b9a402cc50f..9d60a5d322c 100644 --- a/frameworks/Rust/ohkami/src/postgres.rs +++ b/frameworks/Rust/ohkami/src/postgres.rs @@ -2,8 +2,8 @@ use crate::models::{World, Fortune}; use std::sync::Arc; -use futures_util::stream::{StreamExt, FuturesUnordered}; -use rand::{rngs::SmallRng, SeedableRng, Rng, distributions::Uniform, thread_rng}; +use futures_util::stream::{StreamExt, TryStreamExt, FuturesUnordered}; +use rand::{rng, rngs::SmallRng, distr::Uniform, RngExt, SeedableRng}; #[derive(Clone)] pub struct Postgres { @@ -55,44 +55,42 @@ impl Postgres { } impl Postgres { - const ID_RANGE: std::ops::Range = 1..10001; + const ID_RANGE: std::ops::RangeInclusive = 1..=10000; - async fn select_random_world_by_id(&self, id: i32) -> World { + async fn select_random_world_by_id(&self, id: i32) -> Result { let row = self.client .query_one(&self.statements.select_world_by_id, &[&id]) - .await - .expect("failed to fetch a world"); + .await?; - World { + Ok(World { id: row.get(0), randomnumber: row.get(1), - } + }) } } impl Postgres { - pub async fn select_random_world(&self) -> World { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - self.select_random_world_by_id(rng.gen_range(Self::ID_RANGE)).await + pub async fn select_random_world(&self) -> Result { + let mut rng = SmallRng::from_rng(&mut rng()); + self.select_random_world_by_id(rng.random_range(Self::ID_RANGE)).await } - pub async fn select_n_random_worlds(&self, n: usize) -> Vec { - let rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + pub async fn select_n_random_worlds(&self, n: usize) -> Result, tokio_postgres::Error> { + let rng = SmallRng::from_rng(&mut rng()); let selects = FuturesUnordered::new(); - for id in rng.sample_iter(Uniform::new(Self::ID_RANGE.start, Self::ID_RANGE.end)).take(n) { + for id in rng.sample_iter(Uniform::new(Self::ID_RANGE.start(), Self::ID_RANGE.end()).unwrap()).take(n) { selects.push(self.select_random_world_by_id(id)) } - selects.collect::>().await + selects.try_collect().await } - pub async fn select_all_fortunes(&self) -> Vec { + pub async fn select_all_fortunes(&self) -> Result, tokio_postgres::Error> { let mut rows = std::pin::pin!(self .client .query_raw::<_, _, &[i32; 0]>(&self.statements.select_all_fortunes, &[]) - .await - .expect("failed to fetch fortunes") + .await? ); let mut fortunes = Vec::new(); @@ -103,17 +101,17 @@ impl Postgres { }); } - fortunes + Ok(fortunes) } - pub async fn update_randomnumbers_of_n_worlds(&self, n: usize) -> Vec { - let rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + pub async fn update_randomnumbers_of_n_worlds(&self, n: usize) -> Result, tokio_postgres::Error> { + let rng = SmallRng::from_rng(&mut rng()); - let mut worlds = self.select_n_random_worlds(n).await; + let mut worlds = self.select_n_random_worlds(n).await?; let mut ids = Vec::with_capacity(n); let new_randomnumbers = rng - .sample_iter(Uniform::new(Self::ID_RANGE.start, Self::ID_RANGE.end)) + .sample_iter(Uniform::new(Self::ID_RANGE.start(), Self::ID_RANGE.end()).unwrap()) .take(n) .collect::>(); for i in 0..n { @@ -123,9 +121,8 @@ impl Postgres { self.client .execute(&self.statements.update_worlds, &[&ids, &new_randomnumbers]) - .await - .expect("failed to update worlds"); + .await?; - worlds + Ok(worlds) } } diff --git a/frameworks/Rust/pavex/README.md b/frameworks/Rust/pavex/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/pavex/benchmark_config.json b/frameworks/Rust/pavex/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/rama/Cargo.lock b/frameworks/Rust/rama/Cargo.lock index c31e2852e02..ae0ca9e60b7 100644 --- a/frameworks/Rust/rama/Cargo.lock +++ b/frameworks/Rust/rama/Cargo.lock @@ -347,9 +347,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" @@ -2055,11 +2055,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -2941,9 +2940,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", diff --git a/frameworks/Rust/rama/Cargo.toml b/frameworks/Rust/rama/Cargo.toml index 1c4ce26a247..0552dafdb56 100644 --- a/frameworks/Rust/rama/Cargo.toml +++ b/frameworks/Rust/rama/Cargo.toml @@ -61,7 +61,7 @@ tokio-postgres = { version = "0.7" } yarte = "0.15" simd-json = { version = "0.15", optional = true } mime = { version = "0.3", optional = true } -bytes = { version = "1.10" } +bytes = { version = "1.11" } serde_path_to_error = { version = "0.1", optional = true } quick_cache = "0.6" mimalloc = "0.1" diff --git a/frameworks/Rust/rama/README.md b/frameworks/Rust/rama/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/rama/benchmark_config.json b/frameworks/Rust/rama/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/rocket/Cargo.lock b/frameworks/Rust/rocket/Cargo.lock index 3e193d9a3eb..82ae7401afd 100644 --- a/frameworks/Rust/rocket/Cargo.lock +++ b/frameworks/Rust/rocket/Cargo.lock @@ -189,9 +189,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" @@ -1081,11 +1081,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -1604,9 +1603,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", diff --git a/frameworks/Rust/rocket/README.md b/frameworks/Rust/rocket/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/rocket/benchmark_config.json b/frameworks/Rust/rocket/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/rouille/Cargo.toml b/frameworks/Rust/rouille/Cargo.toml deleted file mode 100644 index 9496ee2a778..00000000000 --- a/frameworks/Rust/rouille/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "rouille" -version = "0.1.0" -authors = ["Gökberk Yaltıraklı "] -edition = "2018" - -[dependencies] -rouille = "1.0" -serde_json = "1.0" diff --git a/frameworks/Rust/rouille/benchmark_config.json b/frameworks/Rust/rouille/benchmark_config.json deleted file mode 100644 index 52d06ddd371..00000000000 --- a/frameworks/Rust/rouille/benchmark_config.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "framework": "rouille", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "rouille", - "language": "Rust", - "orm": "raw", - "platform": "Rust", - "webserver": "rouille", - "os": "Linux", - "database_os": "Linux", - "display_name": "rouille", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Rust/rouille/config.toml b/frameworks/Rust/rouille/config.toml deleted file mode 100644 index 94b33471bf3..00000000000 --- a/frameworks/Rust/rouille/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "rouille" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "raw" -platform = "Rust" -webserver = "rouille" -versus = "None" diff --git a/frameworks/Rust/rouille/rouille.dockerfile b/frameworks/Rust/rouille/rouille.dockerfile deleted file mode 100644 index 60d8d1738fa..00000000000 --- a/frameworks/Rust/rouille/rouille.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.44 - -WORKDIR /rouille -COPY src src -COPY Cargo.toml Cargo.toml - -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release - -EXPOSE 8080 - -CMD ["./target/release/rouille"] diff --git a/frameworks/Rust/rouille/src/main.rs b/frameworks/Rust/rouille/src/main.rs deleted file mode 100644 index b0616fe75e4..00000000000 --- a/frameworks/Rust/rouille/src/main.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[macro_use] -extern crate rouille; -#[macro_use] -extern crate serde_json; - -fn main() { - rouille::start_server("0.0.0.0:8080", move |req| { - router!(req, - (GET) (/plaintext) => { - rouille::Response::from_data("text/plain", "Hello, World!") - }, - (GET) (/json) => { - let json = json!({"message": "Hello, World!"}); - rouille::Response::from_data("application/json", json.to_string()) - }, - _ => rouille::Response::empty_404() - ) - }); -} diff --git a/frameworks/Rust/saphir/README.md b/frameworks/Rust/saphir/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/saphir/benchmark_config.json b/frameworks/Rust/saphir/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/saphir/saphir.dockerfile b/frameworks/Rust/saphir/saphir.dockerfile index b3a29b2d498..5d6400b9f84 100644 --- a/frameworks/Rust/saphir/saphir.dockerfile +++ b/frameworks/Rust/saphir/saphir.dockerfile @@ -1,11 +1,10 @@ -FROM rust:latest +FROM rust:1.93 WORKDIR /saphir - -ADD . . +COPY . . RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --quiet EXPOSE 8080 diff --git a/frameworks/Rust/sib/Cargo.toml b/frameworks/Rust/sib/Cargo.toml index 1358100f450..14534469f0d 100644 --- a/frameworks/Rust/sib/Cargo.toml +++ b/frameworks/Rust/sib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sib-techempower" -version = "0.0.1" +version = "0.0.3" authors = ["mail@pooya.ai"] description = "A high-performance, secure, and cross-platform modules optimized for efficiency, scalability, and reliability." documentation = "https://docs.rs/sib" @@ -12,18 +12,26 @@ categories = ["development-tools"] readme = "README.md" [dependencies] -sib = { version = "0.0.15", default-features = false, features = [ +sib = { version = "0.0.17", default-features = false, features = [ "net-h1-server", ] } -bytes = { version = "1.10.1", default-features = false } -heapless = { version = "0.9.1", default-features = false } -http = { version = "1.3.1", default-features = false } +bytes = { version = "1.11.1", default-features = false } +http = { version = "1.4.0", default-features = false, features = ["std"] } mimalloc = { version = "0.1.48", default-features = false, features = [ "secure", ] } num_cpus = { version = "1.17.0", default-features = false } -serde = { version = "1.0.221", default-features = false, features = ["derive"] } -serde_json = { version = "1.0.144", default-features = false, features = [ +serde = { version = "1.0.228", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.149", default-features = false, features = [ + "std", +] } +tracing = { version = "0.1.44", default-features = false, features = [ + "attributes", + "std", +] } +tracing-subscriber = { version = "0.3.22", features = [ + "fmt", + "env-filter", "std", ] } diff --git a/frameworks/Rust/sib/benchmark_config.json b/frameworks/Rust/sib/benchmark_config.json index 55316d46a37..ab0bc82eb86 100644 --- a/frameworks/Rust/sib/benchmark_config.json +++ b/frameworks/Rust/sib/benchmark_config.json @@ -21,4 +21,4 @@ } } ] -} +} \ No newline at end of file diff --git a/frameworks/Rust/sib/sib.dockerfile b/frameworks/Rust/sib/sib.dockerfile index 98c76de2cdd..fc6d4791b44 100644 --- a/frameworks/Rust/sib/sib.dockerfile +++ b/frameworks/Rust/sib/sib.dockerfile @@ -1,11 +1,11 @@ -FROM rust:latest +FROM rust:1.93 -ADD ./ /sib WORKDIR /sib +COPY . . -RUN apt-get update && apt-get install -y cmake clang lld llvm libclang-dev +RUN apt-get update && apt-get install -y cmake clang lld llvm libclang-dev > /dev/null RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --quiet EXPOSE 8080 diff --git a/frameworks/Rust/sib/src/main.rs b/frameworks/Rust/sib/src/main.rs index 0013400cf8a..fb86c1484a5 100644 --- a/frameworks/Rust/sib/src/main.rs +++ b/frameworks/Rust/sib/src/main.rs @@ -1,3 +1,6 @@ +// TechEmpower benchmark tests for Sib with the `net-h1-server` feature enabled +use bytes::Bytes; +use http::StatusCode; use sib::network::http::{ server::{H1Config, HFactory}, session::{HService, Session}, @@ -6,6 +9,8 @@ use sib::network::http::{ #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +const PLAINTEXT_BODY: &[u8] = b"Hello, World!"; +const PLAINTEXT_CONTENT_LENGTH: &str = "13"; #[derive(serde::Serialize)] struct JsonMessage<'a> { message: &'a str, @@ -23,42 +28,24 @@ struct Server; impl HService for Server { fn call(&mut self, session: &mut S) -> std::io::Result<()> { - use core::fmt::Write; - use sib::network::http::h1_session; - if session.req_path() == "/json" { - // Respond with JSON - let mut res: heapless::String<192> = heapless::String::new(); - let json = serde_json::to_vec(&JsonMessage::default())?; - write!( - res, - "HTTP/1.1 200 OK\r\n\ - Server: sib\r\n\ - Date: {}\r\n\ - Content-Type: application/json\r\n\ - Content-Length: {}\r\n\ - \r\n\ - {}", - h1_session::CURRENT_DATE.load(), - &json.len().to_string(), - String::from_utf8_lossy(&json) - ) - .unwrap(); - session.write_all_eom(res.as_bytes()) - } else { - let mut res: heapless::String<160> = heapless::String::new(); - write!( - res, - "HTTP/1.1 200 OK\r\n\ - Server: sib\r\n\ - Date: {}\r\n\ - Content-Type: text/plain\r\n\ - Content-Length: 13\r\n\ - \r\n\ - Hello, World!", - h1_session::CURRENT_DATE.load() - ) - .unwrap(); - session.write_all_eom(res.as_bytes()) + match session.req_path_bytes() { + b"/json" => { + let json = serde_json::to_vec(&JsonMessage::default())?; + let json_len = json.len().to_string(); + + session + .status_code(StatusCode::OK) + .header_str("Content-Type", "application/json")? + .header_str("Content-Length", json_len.as_str())? + .body(json.into()) + .eom() + } + _ => session + .status_code(StatusCode::OK) + .header_str("Content-Type", "text/plain")? + .header_str("Content-Length", PLAINTEXT_CONTENT_LENGTH)? + .body(Bytes::from_static(PLAINTEXT_BODY)) + .eom(), } } } @@ -72,7 +59,7 @@ impl HFactory for Server { } fn main() { - let stack_size = 4 * 1024; // 4 KB stack + let stack_size = 2 * 1024; // 2 KB stack let cpus = num_cpus::get(); sib::init_global_poller(cpus, stack_size); @@ -84,13 +71,14 @@ fn main() { for _ in 0..cpus { let handle = std::thread::spawn(move || { let id = std::thread::current().id(); - println!("Listening {addr} on thread: {id:?}"); + tracing::info!("Listening {addr} on thread: {id:?}"); Server .start_h1( addr, H1Config { io_timeout: std::time::Duration::from_secs(15), stack_size, + ..Default::default() }, ) .unwrap_or_else(|_| panic!("H1 server failed to start for thread {id:?}")) diff --git a/frameworks/Rust/soli/README.md b/frameworks/Rust/soli/README.md new file mode 100644 index 00000000000..2a066384173 --- /dev/null +++ b/frameworks/Rust/soli/README.md @@ -0,0 +1,122 @@ +# [Soli](https://github.com/solisoft/soli_lang) MVC Framework + +## Description + +Soli is a modern, high-performance web framework written in Rust that combines elegant syntax with blazing fast execution. It features a custom programming language with Ruby-like syntax, MVC architecture, hot reload, and built-in HTTP server powered by Hyper. + +* [GitHub Repository](https://github.com/solisoft/soli_lang) +* [Website](https://solisoft.github.io/soli_lang/) +* Cargo package: [solilang](https://crates.io/crates/solilang) + +## Features + +* **High Performance**: Built on Rust with Hyper async HTTP server +* **170,000+ requests/second** on a single server +* **Sub-millisecond response times** for most requests +* Hot reload in development mode +* MVC architecture with controllers, models, and views +* ERB-style templating with layouts and partials +* Built-in JSON support +* WebSocket support with Live View for reactive UIs +* Convention over configuration + +## Architecture + +This benchmark implements the TechEmpower test suite using Soli's MVC framework: + +* **Language**: Soli (custom DSL compiled to bytecode) +* **Runtime**: Rust with Tokio async runtime +* **HTTP Server**: Hyper +* **JSON Serialization**: Native string serialization (optimized for benchmarks) +* **Port**: 3000 + +## Test URLs + +### Test 1: JSON Encoding + +Returns a simple JSON object with a message field. + +```bash +curl http://localhost:3000/json +``` + +**Response:** +```json +{"message": "Hello, World!"} +``` + +### Test 2: Plaintext + +Returns a simple plaintext response. + +```bash +curl http://localhost:3000/plaintext +``` + +**Response:** +``` +Hello, World! +``` + +## Implementation Details + +The benchmark application consists of: + +* `app/controllers/bench_controller.sl` - Controller with plaintext and JSON handlers +* `config/routes.sl` - Route definitions mapping URLs to controller actions +* `soli.dockerfile` - Multi-stage Docker build installing soli from crates.io + +### Controller Example + +```soli +fn plaintext(req: Any) -> Any { + return { + "status": 200, + "headers": { + "Content-Type": "text/plain", + "Server": "soli" + }, + "body": "Hello, World!" + }; +} +``` + +## Performance + +Benchmarked on a standard server (16 cores): + +| Metric | Value | +|--------|-------| +| Requests/sec | 170,000+ | +| Avg Latency | < 1ms | +| Framework Type | Platform | + +## Local Testing + +To test the benchmark locally: + +```bash +cd frameworks/Rust/soli +docker build -f soli.dockerfile -t soli-benchmark . +docker run -p 3000:3000 soli-benchmark + +# Test endpoints +curl http://localhost:3000/plaintext +curl http://localhost:3000/json +``` + +## Running TechEmpower Benchmarks + +To run the full TechEmpower benchmark suite: + +```bash +./tfb --test soli +``` + +This will run the plaintext and JSON serialization tests against the Soli framework. + +## Notes + +* Database tests are not implemented as Soli MVC currently does not have PostgreSQL support +* The framework uses a production-optimized build with caching enabled +* Worker threads are auto-detected based on available CPU cores diff --git a/frameworks/Rust/soli/app/controllers/bench_controller.sl b/frameworks/Rust/soli/app/controllers/bench_controller.sl new file mode 100644 index 00000000000..026fce333fa --- /dev/null +++ b/frameworks/Rust/soli/app/controllers/bench_controller.sl @@ -0,0 +1,12 @@ +// TechEmpower Benchmark Controller +// Implements plaintext and json test endpoints per TechEmpower spec + +// Plaintext endpoint - returns "Hello, World!" as text/plain +fn plaintext(req: Any) -> Any { + return render_text("Hello, World!"); +} + +// JSON endpoint - returns {"message":"Hello, World!"} as application/json +fn json(req: Any) -> Any { + return render_json({ "message": "Hello, World!" }); +} diff --git a/frameworks/Rust/soli/benchmark_config.json b/frameworks/Rust/soli/benchmark_config.json new file mode 100644 index 00000000000..4812ed3cb74 --- /dev/null +++ b/frameworks/Rust/soli/benchmark_config.json @@ -0,0 +1,24 @@ +{ + "framework": "soli", + "maintainers": ["solisoft"], + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 3000, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "soli", + "language": "Rust", + "orm": "Raw", + "platform": "Rust", + "webserver": "soli", + "os": "Linux", + "database_os": "Linux", + "display_name": "Soli", + "notes": "Soli MVC Framework", + "versus": "hyper" + } + }] +} diff --git a/frameworks/Rust/soli/config/routes.sl b/frameworks/Rust/soli/config/routes.sl new file mode 100644 index 00000000000..14c6ead4afd --- /dev/null +++ b/frameworks/Rust/soli/config/routes.sl @@ -0,0 +1,7 @@ +// TechEmpower Benchmark Routes + +// Plaintext endpoint +get("/plaintext", "bench#plaintext"); + +// JSON endpoint +get("/json", "bench#json"); diff --git a/frameworks/Rust/soli/soli.dockerfile b/frameworks/Rust/soli/soli.dockerfile new file mode 100644 index 00000000000..c2f10dd804f --- /dev/null +++ b/frameworks/Rust/soli/soli.dockerfile @@ -0,0 +1,24 @@ +FROM rust:1.93.0 AS builder + +# Install soli from crates.io with locked dependencies +RUN cargo install solilang --locked + +# Runtime stage +FROM debian:testing-20260202-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Copy soli binary from builder +COPY --from=builder /usr/local/cargo/bin/soli /usr/local/bin/soli + +# Copy benchmark application files +COPY app/ /app/app/ +COPY config/ /app/config/ + +EXPOSE 3000 + +CMD ["soli", "serve", "/app", "--port", "3000"] diff --git a/frameworks/Rust/tachyon-concept/benchmark_config.json b/frameworks/Rust/tachyon-concept/benchmark_config.json index 56db2f7293b..dc308a0de75 100644 --- a/frameworks/Rust/tachyon-concept/benchmark_config.json +++ b/frameworks/Rust/tachyon-concept/benchmark_config.json @@ -19,7 +19,8 @@ "database_os": "Linux", "display_name": "Tachyon-Concept", "notes": "", - "versus": "None" + "versus": "None", + "tags": [ "broken" ] }, "ub": { "json_url": "/json", @@ -38,7 +39,8 @@ "database_os": "Linux", "display_name": "Tachyon-Concept-UB", "notes": "", - "versus": "None" + "versus": "None", + "tags": [ "broken" ] } } ] diff --git a/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile b/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile index 4f7ea5501f0..fd72191ab72 100644 --- a/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile +++ b/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile @@ -1,7 +1,8 @@ -FROM rust:latest +FROM rust:1.93 ENV DEBIAN_FRONTEND=noninteractive + WORKDIR /app -RUN rustup install nightly + RUN git clone https://github.com/TachyonConcepts/TachyonConcept . RUN RUSTFLAGS="-C target-cpu=native -C opt-level=3 -C target-feature=+avx2,+bmi2" cargo install --path . RUN cargo clean diff --git a/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile b/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile index 04aedcc6ac1..bc19c0384dd 100644 --- a/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile +++ b/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile @@ -1,7 +1,8 @@ -FROM rust:latest +FROM rust:1.93 ENV DEBIAN_FRONTEND=noninteractive + WORKDIR /app -RUN rustup install nightly + RUN git clone https://github.com/TachyonConcepts/TachyonConcept . RUN RUSTFLAGS="-C target-cpu=native -C opt-level=3 -C target-feature=+avx2,+bmi2" cargo install --path . RUN cargo clean diff --git a/frameworks/Rust/thruster/benchmark_config.json b/frameworks/Rust/thruster/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/tide/README.md b/frameworks/Rust/tide/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/tide/benchmark_config.json b/frameworks/Rust/tide/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/trillium/README.md b/frameworks/Rust/trillium/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/trillium/benchmark_config.json b/frameworks/Rust/trillium/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/vidi/benchmark_config.json b/frameworks/Rust/vidi/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/viz/Cargo.lock b/frameworks/Rust/viz/Cargo.lock new file mode 100644 index 00000000000..b6316a6521f --- /dev/null +++ b/frameworks/Rust/viz/Cargo.lock @@ -0,0 +1,3022 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "annotate-snippets" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" +dependencies = [ + "unicode-width", + "yansi-term", +] + +[[package]] +name = "async-trait" +version = "0.1.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bb8" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188" +dependencies = [ + "async-trait", + "futures-util", + "parking_lot", + "tokio", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buf-min" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d5698cf6842742ed64805705798f8b351fff53fa546fd45c52184bee58dc90" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" + +[[package]] +name = "cc" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "aes-gcm", + "base64 0.22.1", + "percent-encoding", + "rand", + "subtle", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.77", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.77", +] + +[[package]] +name = "diesel" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" +dependencies = [ + "bitflags 2.6.0", + "byteorder", + "diesel_derives", + "itoa", +] + +[[package]] +name = "diesel-async" +version = "0.4.1" +source = "git+https://github.com/weiznich/diesel_async.git?rev=74867bd#74867bd68e3b600709911b5854a598cbec2ae4a3" +dependencies = [ + "async-trait", + "bb8", + "diesel", + "futures-util", + "scoped-futures", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "diesel_derives" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" +dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +dependencies = [ + "syn 2.0.77", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dsl_auto_type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +dependencies = [ + "darling", + "either", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form-data" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9f1255b81bd56192c67475eefa322f44b85440030547cea7664fd5dc248964" +dependencies = [ + "bytes", + "futures-util", + "http", + "httparse", + "memchr", + "mime", + "serde", + "thiserror", + "tracing", +] + +[[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.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "itoap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.5.3", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "markup" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74a887ad620fe1022257343ac77fcdd3720e92888e1b2e66e1b7a4707f453898" +dependencies = [ + "markup-proc-macro", +] + +[[package]] +name = "markup-proc-macro" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab6ee21fd1855134cacf2f41afdf45f1bc456c7d7f6165d763b4647062dd2be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.3", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-tree" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bcb8f8cf1dee5acae79493abe06a4dfb40e34406a420e929ffb8dce1e06cdd" +dependencies = [ + "smallvec", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "postgres-protocol" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rfc7239" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b106a85eeb5b0336d16d6a20eab857f92861d4fbb1eb9a239866fb98fb6a1063" +dependencies = [ + "uncased", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sailfish" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd5f4680149b62b3478f6af08a8f1c37794bc1bc577e28874a4d0c70084d600" +dependencies = [ + "itoap", + "ryu", + "sailfish-macros", + "version_check", +] + +[[package]] +name = "sailfish-compiler" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67087aca4a3886686a88cee6835089c53e6143a0b8c5be01e63e4fe2f6dfe7cb" +dependencies = [ + "filetime", + "home", + "memchr", + "proc-macro2", + "quote", + "serde", + "syn 2.0.77", + "toml 0.8.19", +] + +[[package]] +name = "sailfish-macros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47e31910c5f9230e99992568d05a5968fe4f42a635c3f912c993e9f66a619a5" +dependencies = [ + "proc-macro2", + "sailfish-compiler", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scoped-futures" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" +dependencies = [ + "cfg-if", + "pin-utils", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "serde_json" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sessions-core" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f714658e945893aadd2cb9fea079d0713c795aa13a7960b3a13eeabd9bb1636f" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +dependencies = [ + "dotenvy", + "either", + "heck 0.4.1", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +dependencies = [ + "atoi", + "base64 0.21.7", + "bitflags 2.6.0", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +dependencies = [ + "atoi", + "base64 0.21.7", + "bitflags 2.6.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[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-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "unicode-xid" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "v_eval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9" +dependencies = [ + "regex", + "syn 1.0.109", +] + +[[package]] +name = "v_htmlescape" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" +dependencies = [ + "buf-min", +] + +[[package]] +name = "v_jsonescape" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8219cc464ba10c48c3231a6871f11d26d831c5c45a47467eea387ea7bb10e8" +dependencies = [ + "buf-min", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "viz" +version = "0.1.0" +dependencies = [ + "atoi", + "diesel", + "diesel-async", + "futures-util", + "hyper", + "hyper-util", + "markup", + "nanorand", + "rand", + "sailfish", + "serde", + "sqlx", + "thiserror", + "tokio", + "tokio-postgres", + "v_htmlescape", + "viz 0.8.8", + "yarte", +] + +[[package]] +name = "viz" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d864106fba5d1eb5ba3158ee03ee201d0c727e848599fc68fe2a24c8766df54" +dependencies = [ + "hyper", + "hyper-util", + "tokio", + "tokio-util", + "tracing", + "viz-core", + "viz-router", +] + +[[package]] +name = "viz-core" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8729d75e2cae28979e75f0f579299ab6ab492695f7fef3f6d494d4cdf54858e4" +dependencies = [ + "async-trait", + "bytes", + "cookie", + "form-data", + "futures-util", + "headers", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "mime", + "rfc7239", + "serde", + "serde_json", + "serde_urlencoded", + "sessions-core", + "sync_wrapper", + "thiserror", +] + +[[package]] +name = "viz-router" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e7e1aa37449f1bb37438fa968962255a057b8ed0b40677fe1739295600cfc4" +dependencies = [ + "path-tree", + "serde", + "thiserror", + "viz-core", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.77", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +dependencies = [ + "redox_syscall 0.4.1", + "wasite", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + +[[package]] +name = "yansi-term" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" +dependencies = [ + "winapi", +] + +[[package]] +name = "yarte" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfce1df93f3b16e5272221a559e60bbbaaa71dbc042a43996d223e51a690aab2" +dependencies = [ + "buf-min", + "yarte_derive", + "yarte_helpers", +] + +[[package]] +name = "yarte_codegen" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a79312078b97a195de91a8c1457c2e0d7abd97e6e605f3cdeb01b3c105d2cff" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "yarte_helpers", + "yarte_hir", +] + +[[package]] +name = "yarte_derive" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b296edd7e1a81717b6f794baa2de8dfe89646050847161550b2d963b3ca6fe80" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "v_jsonescape", + "yarte_codegen", + "yarte_helpers", + "yarte_hir", + "yarte_parser", +] + +[[package]] +name = "yarte_helpers" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d1076f8cee9541ea5ffbecd9102f751252c91f085e7d30a18a3ce805ebd3ee" +dependencies = [ + "buf-min", + "chrono", + "dtoa", + "itoa", + "prettyplease", + "ryu", + "serde", + "serde_json", + "syn 1.0.109", + "toml 0.5.11", + "v_htmlescape", + "v_jsonescape", +] + +[[package]] +name = "yarte_hir" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee42d2f704a3b1d8bc111d47a705d1302a0943d85e4c230f4e8300ee0dde4a6" +dependencies = [ + "derive_more", + "proc-macro2", + "quote", + "syn 1.0.109", + "v_eval", + "v_htmlescape", + "yarte_helpers", + "yarte_parser", +] + +[[package]] +name = "yarte_parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "538f72049cf7104e12d5c444048d112cb8fc788a31308afd912442a381ba860c" +dependencies = [ + "annotate-snippets", + "derive_more", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", + "unicode-xid", + "yarte_helpers", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/frameworks/Rust/vortex/.cargo/config.toml b/frameworks/Rust/vortex/.cargo/config.toml new file mode 100644 index 00000000000..db4658f5977 --- /dev/null +++ b/frameworks/Rust/vortex/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.x86_64-unknown-linux-gnu] +rustflags = [ + "-C", "target-cpu=native", + "-C", "link-arg=-fuse-ld=lld", +] + +[build] +# Default target when building inside Linux container +# target = "x86_64-unknown-linux-gnu" diff --git a/frameworks/Rust/vortex/Cargo.lock b/frameworks/Rust/vortex/Cargo.lock new file mode 100644 index 00000000000..1d9731979c9 --- /dev/null +++ b/frameworks/Rust/vortex/Cargo.lock @@ -0,0 +1,175 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "io-uring" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "mimalloc" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "vortex-db" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "nanorand", + "smallvec", + "vortex-io", +] + +[[package]] +name = "vortex-http" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "httparse", + "itoa", + "libc", + "smallvec", +] + +[[package]] +name = "vortex-io" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "io-uring", + "libc", +] + +[[package]] +name = "vortex-json" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "itoa", +] + +[[package]] +name = "vortex-runtime" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "libc", + "vortex-io", +] + +[[package]] +name = "vortex-server" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "libc", + "nanorand", + "vortex-db", + "vortex-http", + "vortex-io", + "vortex-json", + "vortex-runtime", + "vortex-template", +] + +[[package]] +name = "vortex-techempower" +version = "0.1.0" +dependencies = [ + "mimalloc", + "vortex-server", +] + +[[package]] +name = "vortex-template" +version = "0.1.0" +source = "git+https://github.com/yp3y5akh0v/vortex#73cebaf538f62999240f0124fd8b5a52401e978b" +dependencies = [ + "itoa", +] diff --git a/frameworks/Rust/vortex/Cargo.toml b/frameworks/Rust/vortex/Cargo.toml new file mode 100644 index 00000000000..755482d19e9 --- /dev/null +++ b/frameworks/Rust/vortex/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "vortex-techempower" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "vortex-bench" +path = "src/main.rs" + +[dependencies] +vortex-server = { git = "https://github.com/yp3y5akh0v/vortex" } +mimalloc = { version = "0.1", default-features = false } + +[profile.release] +opt-level = 3 +lto = "fat" +codegen-units = 1 +panic = "abort" +overflow-checks = false +debug = false +incremental = false diff --git a/frameworks/Rust/vortex/README.md b/frameworks/Rust/vortex/README.md new file mode 100644 index 00000000000..4bb3f2fae4d --- /dev/null +++ b/frameworks/Rust/vortex/README.md @@ -0,0 +1,35 @@ +# [Vortex](https://github.com/yp3y5akh0v/vortex) web framework + +## Description + +Vortex is a high-performance HTTP framework for Linux, built on io_uring with thread-per-core architecture. + +## Database + +PostgreSQL (custom binary wire protocol). + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:8080/json + +### Test 2: Single Row Query + + http://localhost:8080/db + +### Test 3: Multi Row Query + + http://localhost:8080/queries?q=20 + +### Test 4: Fortunes (Template rendering) + + http://localhost:8080/fortunes + +### Test 5: Update Query + + http://localhost:8080/updates?q=20 + +### Test 6: Plaintext + + http://localhost:8080/plaintext diff --git a/frameworks/Rust/vortex/benchmark_config.json b/frameworks/Rust/vortex/benchmark_config.json new file mode 100644 index 00000000000..916dd30a57e --- /dev/null +++ b/frameworks/Rust/vortex/benchmark_config.json @@ -0,0 +1,31 @@ +{ + "framework": "vortex", + "maintainers": ["yp3y5akh0v"], + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "vortex", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "vortex", + "os": "Linux", + "database_os": "Linux", + "display_name": "vortex", + "notes": "io_uring + thread-per-core + custom PostgreSQL wire protocol", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/vortex/config.toml b/frameworks/Rust/vortex/config.toml new file mode 100644 index 00000000000..a8b827e90fd --- /dev/null +++ b/frameworks/Rust/vortex/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "vortex" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?q=" +urls.update = "/updates?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Rust" +webserver = "vortex" +versus = "None" diff --git a/frameworks/Rust/vortex/run.sh b/frameworks/Rust/vortex/run.sh new file mode 100644 index 00000000000..767c91406b9 --- /dev/null +++ b/frameworks/Rust/vortex/run.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Kernel tuning for maximum network throughput. +# Non-fatal — works when privileged, silently skipped otherwise. +sysctl -w net.core.somaxconn=65535 2>/dev/null || true +sysctl -w net.ipv4.tcp_max_syn_backlog=65535 2>/dev/null || true +sysctl -w net.ipv4.tcp_fastopen=3 2>/dev/null || true +sysctl -w net.ipv4.tcp_tw_reuse=1 2>/dev/null || true +sysctl -w net.ipv4.tcp_fin_timeout=10 2>/dev/null || true +sysctl -w net.ipv4.tcp_slow_start_after_idle=0 2>/dev/null || true +sysctl -w net.ipv4.tcp_no_metrics_save=1 2>/dev/null || true +sysctl -w net.ipv4.tcp_max_tw_buckets=2000000 2>/dev/null || true +sysctl -w net.ipv4.tcp_timestamps=1 2>/dev/null || true +sysctl -w net.ipv4.tcp_sack=1 2>/dev/null || true +sysctl -w net.ipv4.tcp_window_scaling=1 2>/dev/null || true +sysctl -w net.core.netdev_max_backlog=65535 2>/dev/null || true +sysctl -w net.core.default_qdisc=noqueue 2>/dev/null || true +sysctl -w net.ipv4.ip_local_port_range="1024 65535" 2>/dev/null || true +sysctl -w net.core.rmem_max=16777216 2>/dev/null || true +sysctl -w net.core.wmem_max=16777216 2>/dev/null || true +sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216" 2>/dev/null || true +sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216" 2>/dev/null || true +sysctl -w net.core.busy_read=50 2>/dev/null || true +sysctl -w net.core.busy_poll=50 2>/dev/null || true +export VORTEX_SQPOLL=1 +exec vortex diff --git a/frameworks/Rust/vortex/src/app.rs b/frameworks/Rust/vortex/src/app.rs new file mode 100644 index 00000000000..27bc6081aee --- /dev/null +++ b/frameworks/Rust/vortex/src/app.rs @@ -0,0 +1,191 @@ +//! TechEmpower benchmark application — all route handlers and DB logic. + +use vortex_server::{App, RouteAction}; +use vortex_server::http::date::DateCache; +use vortex_server::http::parser; +use vortex_server::http::response::{StaticResponse, DynJsonResponse, DynHtmlResponse}; + +const PLAINTEXT_CT: &[u8] = b"text/plain"; +const PLAINTEXT_BODY: &[u8] = b"Hello, World!"; +const JSON_MESSAGE: &str = "Hello, World!"; +use vortex_server::db; +use vortex_server::db::wire; + +const ROUTE_PLAINTEXT: u8 = 0; +const ROUTE_JSON: u8 = 1; +const ROUTE_DB: u8 = 2; +const ROUTE_QUERIES: u8 = 3; +const ROUTE_FORTUNES: u8 = 4; +const ROUTE_UPDATES: u8 = 5; + +pub struct TfbApp; + +/// Per-DB-connection state for tracking in-flight operations. +pub struct TfbDbState { + op: u8, + ids: Vec, + random_numbers: Vec, + worlds: Vec<(i32, i32)>, + html: Vec, + /// Pre-built Bind+Execute+Sync template for /db endpoint. + db_template: Vec, +} + +/// Offset of the 4-byte i32 param value within the /db wire template. +/// Bind: B(1) + len(4) + portal\0(1) + "w"\0(2) + fmt_count(2) + fmt(2) + param_count(2) + param_len(4) = 18 +const DB_TEMPLATE_PARAM_OFFSET: usize = 18; + +impl Default for TfbDbState { + fn default() -> Self { + // Pre-build the Bind+Execute+Sync template for /db (placeholder param=0) + let mut db_template = Vec::with_capacity(64); + wire::buf_bind_i32(&mut db_template, "w", &[0]); + wire::buf_execute(&mut db_template); + wire::buf_sync(&mut db_template); + Self { + op: 0, + ids: Vec::with_capacity(500), + random_numbers: Vec::with_capacity(500), + worlds: Vec::with_capacity(500), + html: Vec::with_capacity(4096), + db_template, + } + } +} + +impl App for TfbApp { + type DbState = TfbDbState; + + fn classify(buf: &[u8]) -> RouteAction { + match parser::classify_fast(buf) { + parser::Route::Plaintext => RouteAction::Fast(ROUTE_PLAINTEXT), + parser::Route::Json => RouteAction::Fast(ROUTE_JSON), + parser::Route::Db => RouteAction::Db { id: ROUTE_DB, queries: 1 }, + parser::Route::Queries => RouteAction::Db { + id: ROUTE_QUERIES, + queries: db::clamp_queries(parser::parse_queries_param(buf)), + }, + parser::Route::Fortunes => RouteAction::Db { id: ROUTE_FORTUNES, queries: 1 }, + parser::Route::Updates => RouteAction::Db { + id: ROUTE_UPDATES, + queries: db::clamp_queries(parser::parse_queries_param(buf)), + }, + parser::Route::NotFound => RouteAction::NotFound, + } + } + + fn handle_fast(id: u8, recv: &[u8], send: &mut [u8], date: &DateCache) -> (usize, usize) { + let count = parser::count_request_boundaries(recv); + if count == 0 { return (0, 0); } + + let resp_len = match id { + ROUTE_PLAINTEXT => StaticResponse::write(send, date, PLAINTEXT_CT, PLAINTEXT_BODY), + ROUTE_JSON => { + let mut body = [0u8; 64]; + let blen = vortex_server::json::write_message(&mut body, JSON_MESSAGE); + DynJsonResponse::write(send, date, &body[..blen]) + } + _ => return (0, 0), + }; + + // Duplicate response for pipelined requests + let mut offset = resp_len; + for _ in 1..count { + send.copy_within(0..resp_len, offset); + offset += resp_len; + } + (count, offset) + } + + fn db_statements() -> Vec<(&'static str, &'static str, &'static [u32])> { + vec![ + ("w", "SELECT id, randomNumber FROM World WHERE id = $1", &[23]), + ("f", "SELECT id, message FROM Fortune", &[]), + ("ub", "UPDATE world SET randomNumber = w.r FROM (SELECT unnest($1::int[]) AS i, unnest($2::int[]) AS r) AS w WHERE world.id = w.i", &[1007, 1007]), + ] + } + + fn db_start(id: u8, queries: i32, wbuf: &mut Vec, state: &mut TfbDbState) { + state.op = id; + match id { + ROUTE_DB => { + let rid = db::random_world_id(); + wbuf.extend_from_slice(&state.db_template); + wbuf[DB_TEMPLATE_PARAM_OFFSET..DB_TEMPLATE_PARAM_OFFSET + 4] + .copy_from_slice(&rid.to_be_bytes()); + } + ROUTE_QUERIES => { + state.ids.clear(); + for _ in 0..queries { state.ids.push(db::random_world_id()); } + for &id in &state.ids { + wire::buf_bind_i32(wbuf, "w", &[id]); + wire::buf_execute(wbuf); + } + wire::buf_sync(wbuf); + } + ROUTE_FORTUNES => { + wire::buf_bind_no_params(wbuf, "f", &[1, 0]); + wire::buf_execute(wbuf); + wire::buf_sync(wbuf); + } + ROUTE_UPDATES => { + state.ids.clear(); + state.random_numbers.clear(); + for _ in 0..queries { state.ids.push(db::random_world_id()); } + state.ids.sort_unstable(); + for _ in 0..queries { state.random_numbers.push(db::random_world_id()); } + // SELECT each world + batch UPDATE + for &id in &state.ids { + wire::buf_bind_i32(wbuf, "w", &[id]); + wire::buf_execute(wbuf); + } + wire::buf_bind_i32_arrays(wbuf, "ub", &state.ids, &state.random_numbers); + wire::buf_execute(wbuf); + wire::buf_sync(wbuf); + } + _ => {} + } + } + + fn db_finish( + state: &mut TfbDbState, + rbuf: &[u8], + rpos: usize, + send: &mut [u8], + date: &DateCache, + body: &mut [u8], + ) -> usize { + match state.op { + ROUTE_DB => { + match wire::parse_single_world_buf(&rbuf[..rpos]) { + Some((id, rn)) => { + let blen = vortex_server::json::write_world(body, id, rn); + DynJsonResponse::write(send, date, &body[..blen]) + } + None => 0, + } + } + ROUTE_QUERIES => { + state.worlds.clear(); + wire::parse_world_rows_buf(&rbuf[..rpos], &mut state.worlds); + let blen = vortex_server::json::write_worlds(body, &state.worlds); + DynJsonResponse::write(send, date, &body[..blen]) + } + ROUTE_FORTUNES => { + let mut fortunes = [(0i32, &b""[..]); 16]; + let count = wire::parse_fortune_rows_zerocopy(&rbuf[..rpos], &mut fortunes); + vortex_server::template::render_fortunes_zerocopy(&fortunes, count, &mut state.html); + DynHtmlResponse::write(send, date, &state.html) + } + ROUTE_UPDATES => { + state.worlds.clear(); + for i in 0..state.ids.len() { + state.worlds.push((state.ids[i], state.random_numbers[i])); + } + let blen = vortex_server::json::write_worlds(body, &state.worlds); + DynJsonResponse::write(send, date, &body[..blen]) + } + _ => 0, + } + } +} diff --git a/frameworks/Rust/vortex/src/main.rs b/frameworks/Rust/vortex/src/main.rs new file mode 100644 index 00000000000..a3661c3e6fc --- /dev/null +++ b/frameworks/Rust/vortex/src/main.rs @@ -0,0 +1,22 @@ +//! TechEmpower benchmark entry point for Vortex. + +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +mod app; + +fn main() { + eprintln!("=== Vortex TechEmpower Benchmark Server ==="); + + if let Err(e) = vortex_server::Server::::builder() + .addr("0.0.0.0") + .port(8080) + .workers(0) // auto-detect (override with VORTEX_WORKERS env) + .backlog(4096) + .sqpoll(false) // override with VORTEX_SQPOLL=1 env + .run() + { + eprintln!("[vortex] Fatal error: {}", e); + std::process::exit(1); + } +} diff --git a/frameworks/Rust/vortex/vortex.dockerfile b/frameworks/Rust/vortex/vortex.dockerfile new file mode 100644 index 00000000000..c01fa6cc051 --- /dev/null +++ b/frameworks/Rust/vortex/vortex.dockerfile @@ -0,0 +1,72 @@ +FROM rust:1.82-slim-bookworm AS builder + +# Install build deps + LLVM 16 for BOLT +RUN apt-get update && apt-get install -y \ + build-essential pkg-config liburing-dev lld wget gnupg git \ + && wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/llvm-snapshot.gpg \ + && echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-16 main" > /etc/apt/sources.list.d/llvm-16.list \ + && apt-get update && apt-get install -y bolt-16 libbolt-16-dev \ + && ln -s /usr/lib/llvm-16/lib/libbolt_rt_instr.a /usr/lib/libbolt_rt_instr.a \ + && ln -s /usr/lib/llvm-16/lib/libbolt_rt_hugify.a /usr/lib/libbolt_rt_hugify.a \ + && rm -rf /var/lib/apt/lists/* + +RUN rustup component add llvm-tools-preview + +# --- PGO: build and run profgen from vortex framework repo --- +WORKDIR /profgen-build +RUN git clone https://github.com/yp3y5akh0v/vortex . + +RUN RUSTFLAGS="-Ctarget-cpu=native -Clink-arg=-fuse-ld=lld -Cprofile-generate=/tmp/pgo-data" \ + cargo build --release --bin vortex-profgen + +RUN /profgen-build/target/release/vortex-profgen + +RUN LLVM_PROFDATA="$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata" && \ + $LLVM_PROFDATA merge -o /tmp/pgo-merged.profdata /tmp/pgo-data/ + +# --- Benchmark app: build from local source with PGO + emit-relocs for BOLT --- +WORKDIR /app +COPY Cargo.toml Cargo.lock ./ +COPY src ./src + +RUN RUSTFLAGS="-Ctarget-cpu=native -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--emit-relocs -Cprofile-use=/tmp/pgo-merged.profdata" \ + cargo build --release --bin vortex-bench + +# --- BOLT: rebuild profgen with PGO for instrumentation --- +WORKDIR /profgen-build +RUN RUSTFLAGS="-Ctarget-cpu=native -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--emit-relocs -Cprofile-use=/tmp/pgo-merged.profdata" \ + cargo build --release --bin vortex-profgen + +RUN llvm-bolt-16 /profgen-build/target/release/vortex-profgen \ + -instrument \ + -instrumentation-file=/tmp/bolt-prof \ + -o /tmp/vortex-profgen-bolt + +RUN /tmp/vortex-profgen-bolt && \ + llvm-bolt-16 /app/target/release/vortex-bench \ + -data=/tmp/bolt-prof \ + --profile-ignore-hash \ + -reorder-blocks=ext-tsp \ + -reorder-functions=hfsort+ \ + -split-functions \ + -split-all-cold \ + -icf=1 \ + -frame-opt=all \ + -plt=hot \ + -o /app/target/release/vortex-bench-bolted + +# Runtime image +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y \ + liburing2 \ + procps \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /app/target/release/vortex-bench-bolted /usr/local/bin/vortex +COPY run.sh /usr/local/bin/run.sh +RUN chmod +x /usr/local/bin/run.sh + +EXPOSE 8080 + +ENTRYPOINT ["/usr/local/bin/run.sh"] diff --git a/frameworks/Rust/warp-rust/README.md b/frameworks/Rust/warp-rust/README.md old mode 100755 new mode 100644 diff --git a/frameworks/Rust/warp-rust/benchmark_config.json b/frameworks/Rust/warp-rust/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/warp-rust/warp-rust.dockerfile b/frameworks/Rust/warp-rust/warp-rust.dockerfile index 3248e341a91..28edc84c8b5 100644 --- a/frameworks/Rust/warp-rust/warp-rust.dockerfile +++ b/frameworks/Rust/warp-rust/warp-rust.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.70 +FROM rust:1.93 WORKDIR /warp-rust COPY src src diff --git a/frameworks/Rust/water-http/Cargo.toml b/frameworks/Rust/water-http/Cargo.toml index fe22c5a9a68..baccbd91c7c 100644 --- a/frameworks/Rust/water-http/Cargo.toml +++ b/frameworks/Rust/water-http/Cargo.toml @@ -1,45 +1,60 @@ [package] name = "water-http" version = "0.1.0" -edition = "2018" +edition = "2024" + +default-run = "water-http" [dependencies] askama = "0.14.0" -tokio = { version = "1.47.1", features = ["full"] } -water_http = {git = "https://github.com/HassanSharara/water_http.git", branch = "beta", features = ["use_only_http1"],optional = true , version = "3.0.8-beta.5" } +tokio = { version = "1.48.0", features = ["full"] } + +water_http = { rev = "c275d8e", features = ["use_only_http1"],optional = true , version = "4.0.1-beta.96",git = "https://github.com/HassanSharara/water_http"} +#water_http_unrealistic = {package = "water_http" ,features = ["use_io_uring","use_only_http1"],optional = true , version = "3.4.2-beta.4" } smallvec = "1.15.1" nanorand = "0.8.0" tokio-postgres = "0.7.15" sonic-rs = "0.5.5" -bytes = "1.10.1" +bytes = "1.11.0" serde = { version = "1.0.228", features = ["derive","rc"] } futures-util = "0.3.31" num_cpus = "1.17.0" httpdate = "1.0.3" parking_lot = "0.12.5" yarte = { version = "0.15.7" ,features = ["bytes-buf", "json"] } -itoa = {version = "1.0.15" ,optional = true} +#itoa = {version = "1.0.15" ,optional = true} +smallbox = "0.8.8" +mimalloc = "0.1.48" +#chopin-pg = "0.5.18" +water_buffer = {version = "1.2.10",features = ["bytes","unsafe_clone"]} +integer_to_bytes = "0.2.2" + -[[bin]] -name = "plaintext" -path = "src/plaintext.rs" -required-features = ["json_plaintext"] [[bin]] -name = "json" -path = "src/json.rs" -required-features = ["json_plaintext"] +name = "mini" +path = "src/mini.rs" +required-features = ["mini"] + + + -[[bin]] -name = "cache" -path = "src/cached.rs" -required-features = ["cache"] [features] json_plaintext = ["water_http"] db = ["water_http/thread_shared_struct"] -cache = ["water_http/thread_shared_struct","itoa"] -all = ["water_http/thread_shared_struct"] +all = ["water_http","water_http/thread_shared_struct","water_http/cpu_affinity"] +uring = ["water_http","water_http/thread_shared_struct", "water_http/use_io_uring"] +mini = ["water_http","water_http/cpu_affinity"] + +[profile.release] +opt-level = 3 +codegen-units = 1 +panic = 'abort' +lto = "fat" +debug = false +incremental = false +overflow-checks = false diff --git a/frameworks/Rust/water-http/benchmark_config.json b/frameworks/Rust/water-http/benchmark_config.json index 2b28f0476a3..737a2d247d0 100644 --- a/frameworks/Rust/water-http/benchmark_config.json +++ b/frameworks/Rust/water-http/benchmark_config.json @@ -1,8 +1,10 @@ + { "framework": "water-http", + "maintainers": ["HassanSharara"], "tests": [ { - "default": { + "default": { "json_url": "/json", "plaintext_url": "/plaintext", "fortune_url": "/fortunes", @@ -10,8 +12,8 @@ "query_url": "/queries?q=", "update_url": "/updates?q=", "port": 8080, - "approach": "Realistic", - "classification": "Micro", + "approach": "Stripped", + "classification": "Fullstack", "database": "Postgres", "framework": "water_http", "language": "Rust", @@ -20,17 +22,42 @@ "webserver": "water_http", "os": "Linux", "database_os": "Linux", - "display_name": "water_http" + "display_name": "water_http", + "tags": [] }, - "db": { + "mini": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Stripped", + "classification": "Fullstack", + "database": "Postgres", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http [mini]", + "tags": [] + }, + + "tokio": { + "json_url": "/json", + "plaintext_url": "/plaintext", "fortune_url": "/fortunes", "db_url": "/db", "query_url": "/queries?q=", "update_url": "/updates?q=", "port": 8080, "approach": "Realistic", - "classification": "Micro", + "classification": "Fullstack", "database": "Postgres", "framework": "water_http", "language": "Rust", @@ -39,43 +66,20 @@ "webserver": "water_http", "os": "Linux", "database_os": "Linux", - "display_name": "water_http" + "display_name": "water_http [uns]" }, - "cached": { - "cached_query_url": "/cached-queries?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "water_http", - "language": "Rust", - "orm": "raw", - "platform": "Rust", - "webserver": "water_http", - "os": "Linux", - "database_os": "Linux", - "display_name": "water_http" - }, - "json": { + "uring": { "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "framework": "water_http", - "language": "Rust", - "orm": "raw", - "platform": "Rust", - "webserver": "water_http", - "os": "Linux", - "database_os": "Linux", - "display_name": "water_http" - }, - "plaintext": { "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8080, "approach": "Realistic", - "classification": "Micro", + "classification": "Fullstack", + "database": "Postgres", "framework": "water_http", "language": "Rust", "orm": "raw", @@ -83,8 +87,8 @@ "webserver": "water_http", "os": "Linux", "database_os": "Linux", - "display_name": "water_http" + "display_name": "water_http [io-uring]" } } - ] + ] } \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/buf.rs b/frameworks/Rust/water-http/src/buf.rs new file mode 100644 index 00000000000..b58806e1067 --- /dev/null +++ b/frameworks/Rust/water-http/src/buf.rs @@ -0,0 +1,189 @@ +use std::cell::RefCell; +use crate::models::{Fortune, World}; +// Assuming water_buffer crate exists +// use water_buffer::WaterBuffer as BM; + +// Mocking the type for compilation demo +type WaterBuffer = Vec; + + +const INITIAL_VEC_CAPACITY: usize = 2000; +const DEFAULT_SIZE: usize = 4048; +const MAX_BUFFER_SIZE: usize = 4048; // Allow some growth before discarding +const MAX_CACHED_BUFFERS: usize = 512; // Set to your test requirement + + +thread_local! { + static BUFFER_CACHE: RefCell> = RefCell::new(Vec::with_capacity(INITIAL_VEC_CAPACITY)); + static FORTUNE_CACHE: RefCell>> = RefCell::new(Vec::with_capacity(INITIAL_VEC_CAPACITY)); + static WORLDS_CACHE: RefCell>> = RefCell::new(Vec::with_capacity(500)); + static IDS_NUMBERS: RefCell,Vec)>> = RefCell::new(Vec::with_capacity(500)); + +} + +pub struct PooledBuffer { + inner: Option, +} + +pub struct FortunesPool { + inner: Option>, +} + +pub struct WorldsPool { + inner: Option>, +} + +pub struct IDsPool { + inner: Option<(Vec,Vec)>, +} + + +impl PooledBuffer { + pub fn new() -> Self { + Self::with_capacity(DEFAULT_SIZE) + } + + pub fn with_capacity(cap: usize) -> Self { + let buf = BUFFER_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if let Some(mut existing_buf) = cache.pop() { + // Assuming your WaterBuffer has a clear/reset method + existing_buf.clear(); + existing_buf + } else { + // Fallback to new allocation if cache is empty + WaterBuffer::with_capacity(cap) + } + }); + + Self { inner: Some(buf) } + } + + pub fn take_inner(&mut self) -> WaterBuffer { + self.inner.take().expect("Buffer already taken or dropped") + } + + pub fn recycle(buf: WaterBuffer) { + // Use capacity() check to ensure we don't cache + // a buffer that grew to a massive size during one specific request + if buf.capacity() <= MAX_BUFFER_SIZE { + BUFFER_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if cache.len() < MAX_CACHED_BUFFERS { + cache.push(buf); + } + }); + } + } +} +impl FortunesPool { + pub fn new() -> Self { + Self::with_capacity(16) + } + + pub fn with_capacity(cap: usize) -> Self { + let buf = FORTUNE_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if let Some(mut existing_buf) = cache.pop() { + // Assuming your WaterBuffer has a clear/reset method + existing_buf + } else { + // Fallback to new allocation if cache is empty + Vec::with_capacity(cap) + } + }); + + Self { inner: Some(buf) } + } + + pub fn take_inner(&mut self) -> Vec { + self.inner.take().expect("Buffer already taken or dropped") + } + + pub fn save_heap_allocation(buf: WaterBuffer) { + // Use capacity() check to ensure we don't cache + // a buffer that grew to a massive size during one specific request + if buf.capacity() <= 16 { + BUFFER_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if cache.len() < 2000 { + cache.push(buf); + } + }); + } + } +} +impl WorldsPool { + pub fn new() -> Self { + Self::with_capacity(500) + } + + pub fn with_capacity(cap: usize) -> WorldsPool { + let buf = WORLDS_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if let Some(mut existing_buf) = cache.pop() { + // Assuming your WaterBuffer has a clear/reset method + existing_buf + } else { + // Fallback to new allocation if cache is empty + Vec::with_capacity(cap) + } + }); + + Self { inner: Some(buf) } + } + + pub fn take_inner(&mut self) -> Vec { + self.inner.take().expect("Buffer already taken or dropped") + } + + pub fn save_heap_allocation(buf: Vec) { + // Use capacity() check to ensure we don't cache + // a buffer that grew to a massive size during one specific request + if buf.capacity() <= 500 { + WORLDS_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + if cache.len() < 2000 { + cache.push(buf); + } + }); + } + } +} +impl IDsPool { + pub fn new() -> Self { + Self::with_capacity(500) + } + + pub fn with_capacity(cap: usize) -> IDsPool { + let buf = IDS_NUMBERS.with(|cache| { + let mut cache = cache.borrow_mut(); + if let Some(mut existing_buf) = cache.pop() { + existing_buf.0.clear(); + existing_buf.1.clear(); + existing_buf + } else { + // Fallback to new allocation if cache is empty + (Vec::with_capacity(cap),Vec::with_capacity(cap)) + } + }); + + Self { inner: Some(buf) } + } + + pub fn take_inner(&mut self) -> (Vec,Vec) { + self.inner.take().expect("Buffer already taken or dropped") + } + + pub fn save_heap_allocation(buf: (Vec,Vec)) { + // Use capacity() check to ensure we don't cache + // a buffer that grew to a massive size during one specific request + IDS_NUMBERS.with(|cache| { + let mut cache = cache.borrow_mut(); + if cache.len() < 1000 { + cache.push(buf); + } + }); + } +} + diff --git a/frameworks/Rust/water-http/src/cached.rs b/frameworks/Rust/water-http/src/cached.rs deleted file mode 100644 index 6e1cea1a77f..00000000000 --- a/frameworks/Rust/water-http/src/cached.rs +++ /dev/null @@ -1,305 +0,0 @@ -#![allow(static_mut_refs)] -use std::io; -use std::fmt::Arguments; -use std::io::Write; -use std::mem::MaybeUninit; -use std::rc::Rc; -use std::cell::UnsafeCell; -use std::collections::HashMap; -use nanorand::{Rng, WyRand}; -use tokio_postgres::{connect, Client, NoTls}; -use tokio_postgres::types::private::BytesMut; -use sonic_rs::prelude::WriteExt; -use std::pin::Pin; -use tokio::task::LocalSet; -use water_http::{InitControllersRoot, RunServer, WaterController}; -use water_http::http::{HttpSender, ResponseData}; -use water_http::server::{HttpContext, ServerConfigurations}; -use water_http::http::HttpSenderTrait; - -pub struct DbConnectionPool { - pub connections: Vec>, - pub next: UnsafeCell, -} - -impl DbConnectionPool { - /// Get a connection from the pool (round-robin, relaxed ordering) - #[inline(always)] - pub fn get_connection(&self) -> &Rc { - let n = unsafe{&mut *self.next.get()}; - *n +=1; - let idx = *n % self.connections.len(); - unsafe { self.connections.get_unchecked(idx) } - } - - /// Fill the pool with connections - pub async fn fill_pool(&mut self, url: &'static str, size: usize) { - let mut tasks = Vec::with_capacity(size); - for _ in 0..size { - tasks.push(tokio::task::spawn_local(async move { - for attempt in 0..5 { - match PgConnection::connect(url).await { - Ok(conn) => { - - return Ok(conn); }, - Err(_) if attempt < 4 => { - tokio::time::sleep(std::time::Duration::from_millis(100)).await; - } - Err(_) => return Err(()), - } - } - Err(()) - })); - } - for t in tasks { - if let Ok(Ok(conn)) = t.await { - self.connections.push(Rc::new(conn)); - } - } - } - - -} - - - - -pub struct PgConnection { - cl:Client, - _connection_task: tokio::task::JoinHandle<()>, -} - -// Safety: Only used within LocalSet, no cross-thread access -impl PgConnection { - /// Connect to the database - - pub async fn connect(db_url: &str) -> Result { - let (cl, c) = tokio::time::timeout( - std::time::Duration::from_secs(5), - connect(db_url, NoTls), - ) - .await - .map_err(|_| ())? - .map_err(|_| ())?; - - let connection_task = tokio::task::spawn_local(async move { - let _ = c.await; - }); - - Ok(PgConnection { - _connection_task: connection_task, - cl - }) - } -} - -/// Zero-copy writer for BytesMut -pub struct BytesMuteWriter<'a>(pub &'a mut BytesMut); - -impl BytesMuteWriter<'_> { - - #[inline(always)] - pub fn extend_from_slice(&mut self,data:&[u8]){ - self.0.extend_from_slice(data); - } -} - -impl Write for BytesMuteWriter<'_> { - #[inline(always)] - fn write(&mut self, src: &[u8]) -> Result { - self.0.extend_from_slice(src); - Ok(src.len()) - } - - #[inline(always)] - fn flush(&mut self) -> Result<(), io::Error> { - Ok(()) - } -} - -impl std::fmt::Write for BytesMuteWriter<'_> { - #[inline(always)] - fn write_str(&mut self, s: &str) -> std::fmt::Result { - self.0.extend_from_slice(s.as_bytes()); - Ok(()) - } - - #[inline(always)] - fn write_char(&mut self, c: char) -> std::fmt::Result { - let mut buf = [0u8; 4]; - self.0.extend_from_slice(c.encode_utf8(&mut buf).as_bytes()); - Ok(()) - } - - #[inline(always)] - fn write_fmt(&mut self, args: Arguments<'_>) -> std::fmt::Result { - std::fmt::write(self, args) - } -} - -impl WriteExt for BytesMuteWriter<'_> { - #[inline(always)] - fn reserve_with(&mut self, additional: usize) -> Result<&mut [MaybeUninit], io::Error> { - self.0.reserve(additional); - unsafe { - let ptr = self.0.as_mut_ptr().add(self.0.len()) as *mut MaybeUninit; - Ok(std::slice::from_raw_parts_mut(ptr, additional)) - } - } - - #[inline(always)] - unsafe fn flush_len(&mut self, additional: usize) -> io::Result<()> { - self.0.set_len(self.0.len() + additional); - Ok(()) - } -} - - -InitControllersRoot! { - name:ROOT, - holder_type:MainType, - shared_type:SH, -} - -pub struct ThreadSharedStruct{ - writing_buffer:UnsafeCell, - rng:WyRand, -} - - -impl ThreadSharedStruct { - - #[inline(always)] - pub fn get_value(id:i32)->&'static i32{ - let map = unsafe {CACHED_VALUES.as_ref().unwrap().get(&id)} ; - map.unwrap() - } - pub fn get_cached_queries(&self,num:usize)->&[u8]{ - let buf = unsafe{&mut *(self.writing_buffer.get())}; - buf.clear(); - buf.extend_from_slice(br#"["#); - let mut writer = BytesMuteWriter(buf); - let mut rn = self.rng.clone(); - for _ in 0..num { - let rd: i32 = (rn.generate::() & 0x3FFF) as i32 % 10_000 + 1; - let v = Self::get_value(rd); - writer.extend_from_slice(br"{"); - _ = write!(writer, r#""id":{},"randomnumber":{}"#, rd, v); - writer.extend_from_slice(br"},"); - } - if buf.len() >1 {buf.truncate(buf.len() - 1);} - buf.extend_from_slice(b"]"); - return &buf[..] - } -} - -pub type MainType = u8; -pub type SH = Rc; - - -static mut CACHED_VALUES:Option> = None; - -pub fn run_server(){ - - _= std::thread::spawn( - ||{ - let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async move { - const URL:&'static str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - // const URL:&'static str = "postgres://postgres:root@localhost:5432/techmpower"; - - let mut pool = DbConnectionPool{ - connections:Vec::with_capacity( 1 - ), - next:0.into(), - // rt:tokio::runtime::Builder::new_multi_thread().enable_all().worker_threads(cpu_nums).build().unwrap() - }; - - let local_set = LocalSet::new(); - - _= local_set.run_until(async move { - tokio::task::spawn_local(async move { - pool.fill_pool(URL, 1).await; - let connection = pool.get_connection(); - let statement = connection.cl.prepare("SELECT id,randomnumber FROM World").await.unwrap(); - let res = connection.cl.query(&statement,&[]).await.unwrap(); - let mut map = HashMap::new(); - for row in res { - map.insert(row.get(0),row.get(1)); - } - unsafe { - let static_map = &mut CACHED_VALUES; - *static_map = Some(map); - } - }).await - }).await; - - }); - } - ).join(); - let cpu_nums = num_cpus::get(); - - - println!("start listening on port 8080 while workers count {cpu_nums}"); - let mut conf = ServerConfigurations::bind("0.0.0.0",8080); - conf.worker_threads_count = cpu_nums * 1 ; - - // let addresses = (0..cpu_nums).map(|_| { - // ("0.0.0.0".to_string(),8080) - // }).collect::>(); - // conf.addresses = addresses; - RunServer!( - conf, - ROOT, - EntryController, - shared_factory - ); -} - -fn shared_factory()->Pin>>{ - Box::pin(async { - - // const URL:&'static str = "postgres://postgres:root@localhost:5432/techmpower"; - - Rc::new(ThreadSharedStruct{ - writing_buffer:UnsafeCell::new(BytesMut::with_capacity(100_000)), - rng:WyRand::new() - }) - }) -} - -pub async fn handle_cached_queries(context:&mut HttpContext<'_,MainType,SH,HS,QS>){ - let q = context - .get_from_path_query("q") - .and_then(|v| v.parse::().ok()) // safely parse - .unwrap_or(1) // default to 1 if missing or invalid - .clamp(1, 500); - - let connection:SH = context.thread_shared_struct.clone().unwrap().clone(); - let data = connection.get_cached_queries(q); - let mut sender:HttpSender = context.sender(); - sender.set_header_ef("Content-Type","application/json"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _= sender.send_data_as_final_response( - ResponseData::Slice(data) - ).await; -} - -WaterController! { - holder -> super::MainType, - shared -> super::SH, - name -> EntryController, - functions -> { - - GET -> "cached-queries" -> query (context) { - _=super::handle_cached_queries(context).await; - } - } -} - -fn main() { - run_server(); -} - diff --git a/frameworks/Rust/water-http/src/date.rs b/frameworks/Rust/water-http/src/date.rs new file mode 100644 index 00000000000..0896f479733 --- /dev/null +++ b/frameworks/Rust/water-http/src/date.rs @@ -0,0 +1,32 @@ +use std::cell::UnsafeCell; +use std::time::{SystemTime, UNIX_EPOCH}; + +thread_local! { + // We store the bytes directly in the Thread Local Storage (TLS) + // to ensure the reference stays valid for the life of the thread. + static CACHED_DATE: UnsafeCell<(u64, [u8; 29])> = UnsafeCell::new((0, [0u8; 29])); +} + +#[inline(always)] +pub fn get_date_fast() -> &'static str { + CACHED_DATE.with(|cell| { + unsafe { + let cache = &mut *cell.get(); + // 1. Use a fast duration check + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_unchecked() // Benchmark trick: avoid panic branches + .as_secs(); + + if now != cache.0 { + cache.0 = now; + let date_str = httpdate::fmt_http_date(SystemTime::now()); + cache.1.copy_from_slice(date_str.as_bytes()); + } + + // 2. Return a reference to the TLS memory directly. + // This is safe because the thread never dies during the benchmark. + std::str::from_utf8_unchecked(&cache.1) + } + }) +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/db.rs b/frameworks/Rust/water-http/src/db.rs index 40640735f88..db6f3028199 100644 --- a/frameworks/Rust/water-http/src/db.rs +++ b/frameworks/Rust/water-http/src/db.rs @@ -1,17 +1,23 @@ -#![cfg(any(feature = "db",feature = "all"))] +#![cfg(any(feature = "db",feature = "all",feature = "uring",feature = "mini"))] use std::{borrow::Cow, io}; use std::fmt::Arguments; use std::io::Write; use std::mem::MaybeUninit; use std::rc::Rc; use std::cell::UnsafeCell; -use bytes::Buf; +use bytes::{Buf, BufMut}; use nanorand::{Rng, WyRand}; +use smallvec::SmallVec; use tokio_postgres::{connect, Client, Statement, NoTls}; use tokio_postgres::types::private::BytesMut; use crate::models::{Fortune, FortuneTemplate, World}; use sonic_rs::prelude::WriteExt; +use water_buffer::WaterBuffer; use yarte::TemplateBytesTrait; +use crate::buf::{FortunesPool, IDsPool, PooledBuffer, WorldsPool}; + + +use tokio::pin; /// Database connection pool with thread-local RNG pub struct DbConnectionPool { @@ -19,6 +25,9 @@ pub struct DbConnectionPool { pub next: UnsafeCell, } +unsafe impl Sync for DbConnectionPool {} +unsafe impl Send for DbConnectionPool {} + impl DbConnectionPool { /// Get a connection from the pool (round-robin, relaxed ordering) #[inline(always)] @@ -33,7 +42,7 @@ impl DbConnectionPool { pub async fn fill_pool(&mut self, url: &'static str, size: usize) { let mut tasks = Vec::with_capacity(size); for _ in 0..size { - tasks.push(tokio::task::spawn_local(async move { + tasks.push(tokio::task::spawn(async move { for attempt in 0..5 { match PgConnection::connect(url).await { Ok(conn) => { @@ -88,7 +97,6 @@ pub struct PgConnection { pub updates: Vec, rang:WyRand, buffers: UnsafeCell, - _connection_task: tokio::task::JoinHandle<()>, } // Safety: Only used within LocalSet, no cross-thread access @@ -104,7 +112,7 @@ impl PgConnection { .map_err(|_| ())? .map_err(|_| ())?; - let connection_task = tokio::task::spawn_local(async move { + _= tokio::task::spawn(async move { let _ = conn.await; }); @@ -113,7 +121,7 @@ impl PgConnection { // Pre-compile update statements for batch sizes 1-500 let mut updates = vec![]; - for num in 1..=500 { + for num in 1..=500 { let sql = Self::generate_update_values_stmt(num); updates.push(cl.prepare(&sql).await.unwrap()); } @@ -124,14 +132,12 @@ impl PgConnection { world, updates, buffers: UnsafeCell::new(BufferPool::new()), - _connection_task: connection_task, rang: WyRand::new() }) - } /// Connect to the database - + } + /// Connect to the database #[inline(always)] - pub fn generate_update_values_stmt(batch_size: usize) -> String { - + pub fn generate_update_values_stmt(batch_size: usize) -> String { let mut sql = String::from("UPDATE world SET randomNumber = w.r FROM (VALUES "); for i in 0..batch_size { @@ -155,40 +161,40 @@ impl PgConnection { /// Get a single random world - optimized with buffer reuse #[inline] - pub async fn get_world(&self) -> &[u8] { + pub async fn get_world(&self) -> Vec { let rd = (self.rang.clone().generate::() % 10_000 + 1) as i32; let row = self.cl.query_one(&self.world, &[&rd]).await.unwrap(); - let buffers = self.buffers(); - buffers.body.clear(); + let mut buffer = PooledBuffer::new().take_inner(); sonic_rs::to_writer( - BytesMuteWriter(&mut buffers.body), + &mut buffer, &World { id: row.get(0), randomnumber: row.get(1), }, ).unwrap(); - buffers.body.chunk() + buffer } /// Get multiple random worlds - optimized with buffer reuse - pub async fn get_worlds(&self, num: usize) -> &[u8] { - let buffers = self.buffers(); - buffers.worlds.clear(); + pub async fn get_worlds(&self, num: usize) -> Vec { + let mut worlds = WorldsPool::new().take_inner(); + worlds.clear(); let mut rn = self.rang.clone(); for _ in 0..num { let id: i32 = (rn.generate::() & 0x3FFF) as i32 % 10_000 + 1; let row = self.cl.query_one(&self.world, &[&id]).await.unwrap(); - buffers.worlds.push(World { + worlds.push(World { id: row.get(0), randomnumber: row.get(1), }); } - buffers.body.clear(); - sonic_rs::to_writer(BytesMuteWriter(&mut buffers.body), &buffers.worlds).unwrap(); - buffers.body.chunk() + let mut buffer = PooledBuffer::new().take_inner(); + sonic_rs::to_writer(&mut buffer, &worlds).unwrap(); + WorldsPool::save_heap_allocation(worlds); + buffer } /// Update worlds in batch - optimized with buffer reuse /// Update worlds in batch - optimized with buffer reuse @@ -200,72 +206,123 @@ impl PgConnection { /// Update worlds in batch - optimized with RETURNING clause to minimize reads /// Update worlds - fetch and update each row to handle duplicates correctly /// Update worlds in batch using CASE statement - pub async fn update(&self, num: usize) -> &[u8] { - let buffers = self.buffers(); - let mut ids:Vec = Vec::with_capacity(num); - let mut rng = self.rang.clone(); + pub async fn update(&self,num:usize)->Vec{ + + let mut output = PooledBuffer::new().take_inner(); + let (mut ids,mut numbers) = IDsPool::new().take_inner(); + let mut worlds = WorldsPool::new().take_inner(); + let mut rn = self.rang.clone(); + let mut futures = Vec::with_capacity(num); let mut params: Vec<&(dyn tokio_postgres::types::ToSql + Sync)> = - Vec::with_capacity(num * 2); - let mut futures =vec![]; - for _ in 0..num { - let w_id = (rng.generate::() % 10_000 + 1) as i32; - ids.push(w_id); - } - futures.extend(ids.iter().map(|x| async move {self.cl.query_one(&self.world,&[&x]).await})); - futures_util::future::join_all(futures).await; - ids.sort_unstable(); - buffers.worlds.clear(); - for index in 0..num { - let s_id = (rng.generate::() % 10_000 + 1 ) as i32; - buffers.worlds.push(World{ - id:ids[index], - randomnumber:s_id + Vec::with_capacity(num * 2); + + if worlds.len() == num { + for w in &worlds { + ids.push(w.id); + params.push(&w.id); + numbers.push(w.randomnumber); + params.push(&w.randomnumber); + } + } else { + worlds.clear(); + (0..num).for_each(|n|{ + let id = (rn.generate::() % 10_000 + 1) as i32; + let number = (rn.generate::() % 10_000 + 1) as i32; + ids.push(id); + numbers.push(number); }); - buffers.numbers.push(s_id); - } - buffers.body.clear(); - for index in 0..num { - params.push(&ids[index]); - params.push(&buffers.numbers[index]); - } - _=self.cl.execute(&self.updates[num - 1], ¶ms).await.unwrap(); - sonic_rs::to_writer(BytesMuteWriter(&mut buffers.body), &buffers.worlds).unwrap(); - buffers.body.chunk() + ids.sort(); + for ind in 0..num { + worlds.push( + World{ + id:ids[ind], + randomnumber:numbers[ind] + } + ); + params.push(&ids[ind]); + params.push(&numbers[ind]); + } + } + futures.extend(ids.iter().map(|x| async move { self.cl.query_one(&self.world, &[&x]).await })); + futures_util::future::join_all(futures).await; + _ = self.cl.execute(&self.updates[num - 1], ¶ms).await; + _= sonic_rs::to_writer(&mut output,&worlds); + WorldsPool::save_heap_allocation(worlds); + IDsPool::save_heap_allocation((ids,numbers)); + output } - - /// Tell fortunes - optimized with buffer reuse - pub async fn tell_fortune(&self) -> Result<&[u8], ()> { - let res = self.cl.query(&self.fortune, &[]).await.map_err(|_| ())?; - - let buffers = self.buffers(); - buffers.fortunes.clear(); - buffers.fortune_output.clear(); - - buffers.fortunes.push(Fortune { - id: 0, - message: Cow::Borrowed("Additional fortune added at request time."), - }); - - for row in res { - buffers.fortunes.push(Fortune { - id: row.get(0), - message: Cow::Owned(row.get(1)), - }); + // pub async fn update(&self, num: usize) -> &[u8] { + // let buffers = self.buffers(); + // let mut ids: Vec = Vec::with_capacity(num); + // let mut rng = self.rang.clone(); + // let mut params: Vec<&(dyn tokio_postgres::types::ToSql + Sync)> = + // Vec::with_capacity(num * 2); + // let mut futures = vec![]; + // for _ in 0..num { + // let w_id = (rng.generate::() % 10_000 + 1) as i32; + // ids.push(w_id); + // } + // futures.extend(ids.iter().map(|x| async move { self.cl.query_one(&self.world, &[&x]).await })); + // futures_util::future::join_all(futures).await; + // ids.sort_unstable(); + // buffers.worlds.clear(); + // for index in 0..num { + // let s_id = (rng.generate::() % 10_000 + 1) as i32; + // buffers.worlds.push(World { + // id: ids[index], + // randomnumber: s_id + // }); + // buffers.numbers.push(s_id); + // } + // buffers.body.clear(); + // for index in 0..num { + // params.push(&ids[index]); + // params.push(&buffers.numbers[index]); + // } + // + // _ = self.cl.execute(&self.updates[num - 1], ¶ms).await.unwrap(); + // sonic_rs::to_writer(BytesMuteWriter(&mut buffers.body), &buffers.worlds).unwrap(); + // buffers.body.chunk() + // } + + + pub async fn tell_fortune(&self) -> Result, ()> { + // 1. Explicitly type the empty params to satisfy the compiler's inference + let mut res = self.cl.query(&self.fortune, &[]).await.unwrap(); + let mut fortunes = FortunesPool::new().take_inner(); + if fortunes.is_empty() { + fortunes.push(Fortune{ + id:0, + message:Cow::Borrowed("Additional fortune added at request time.") + }); + for r in res { + let id :&'static str = unsafe { + let a :&str = r.get(1); + &*(a as *const str) + }; + fortunes.push( + Fortune { + id:r.get(0), + message:Cow::Borrowed(id) + } + ); + } + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); } - - buffers.fortunes.sort_unstable_by(|a, b| a.message.cmp(&b.message)); - - let template = FortuneTemplate { items: &buffers.fortunes }; - template.write_call(&mut buffers.fortune_output); - - // Return reference to buffer - zero-copy! - Ok(&buffers.fortune_output) + let mut output = PooledBuffer::new().take_inner(); + let template = FortuneTemplate { + items: &fortunes, + }; + template.write_call(&mut output); + Ok(output) } } +unsafe impl Sync for PgConnection {} +unsafe impl Send for PgConnection {} /// Zero-copy writer for BytesMut pub struct BytesMuteWriter<'a>(pub &'a mut BytesMut); @@ -317,4 +374,62 @@ impl WriteExt for BytesMuteWriter<'_> { self.0.set_len(self.0.len() + additional); Ok(()) } +} + +/// Zero-copy writer for WaterBuffer +pub struct WaterMutWriter<'a>(pub &'a mut WaterBuffer); + +impl Write for WaterMutWriter<'_> { + #[inline(always)] + fn write(&mut self, src: &[u8]) -> Result { + self.0.extend_from_slice(src); + Ok(src.len()) + } + + #[inline(always)] + fn flush(&mut self) -> Result<(), io::Error> { + Ok(()) + } +} + +impl std::fmt::Write for WaterMutWriter<'_> { + #[inline(always)] + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.0.extend_from_slice(s.as_bytes()); + Ok(()) + } + + #[inline(always)] + fn write_char(&mut self, c: char) -> std::fmt::Result { + let mut buf = [0u8; 4]; + self.0 + .extend_from_slice(c.encode_utf8(&mut buf).as_bytes()); + Ok(()) + } + + #[inline(always)] + fn write_fmt(&mut self, args: Arguments<'_>) -> std::fmt::Result { + std::fmt::write(self, args) + } +} + +impl WriteExt for WaterMutWriter<'_> { + #[inline(always)] + fn reserve_with( + &mut self, + additional: usize, + ) -> Result<&mut [MaybeUninit], io::Error> { + self.0.reserve(additional); + + unsafe { + let ptr = self.0.as_mut_ptr().add(self.0.len()) as *mut MaybeUninit; + Ok(std::slice::from_raw_parts_mut(ptr, additional)) + } + } + + #[inline(always)] + unsafe fn flush_len(&mut self, additional: usize) -> io::Result<()> { + self.0.advance_mut(self.0.len() + additional); + Ok(()) + } } \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/json.rs b/frameworks/Rust/water-http/src/json.rs deleted file mode 100644 index 71f406b6051..00000000000 --- a/frameworks/Rust/water-http/src/json.rs +++ /dev/null @@ -1,55 +0,0 @@ -use water_http::{InitControllersRoot, RunServer, WaterController}; -use water_http::server::ServerConfigurations; - -InitControllersRoot! { - name:ROOT, - holder_type:MainType, -} - - - -pub type MainType = u8; - - -fn main() { - run_server(); -} - - -pub fn run_server(){ - - let cpu_nums = num_cpus::get(); - - - println!("start listening on port 8080 while workers count {cpu_nums}"); - let mut conf = ServerConfigurations::bind("0.0.0.0",8080); - conf.worker_threads_count = cpu_nums * 2 ; - - RunServer!( - conf, - ROOT, - EntryController - ); -} - -const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; - - -WaterController! { - holder -> super::MainType, - name -> EntryController, - functions -> { - - - GET => json => j(cx){ - let mut sender = cx.sender(); - sender.set_header_ef("Content-Type","application/json"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _=sender.send_data_as_final_response(http::ResponseData::Slice(super::JSON_RESPONSE)).await; - } - - } -} - diff --git a/frameworks/Rust/water-http/src/main.rs b/frameworks/Rust/water-http/src/main.rs index 487409af1d6..61282df5f00 100644 --- a/frameworks/Rust/water-http/src/main.rs +++ b/frameworks/Rust/water-http/src/main.rs @@ -1,7 +1,21 @@ -mod server; +pub mod server; pub mod models; -mod db; +pub mod db; +pub mod date; +pub mod buf; -fn main() { - server::run_server(); +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + + fn main() { + + #[cfg(feature = "mini")] + { + mini::run(); + } + #[cfg(not(feature = "mini"))] + server::run_server(); } + diff --git a/frameworks/Rust/water-http/src/mini.rs b/frameworks/Rust/water-http/src/mini.rs new file mode 100644 index 00000000000..d43a22fd439 --- /dev/null +++ b/frameworks/Rust/water-http/src/mini.rs @@ -0,0 +1,167 @@ +use std::cell::OnceCell; +use water_http::http::status_code::HttpStatusCode; +use water_http::server::mini::{CtxPtr, HandlerFn, serve}; +use water_http::server::ServerConfigurations; +use crate::buf::{FortunesPool, PooledBuffer}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + + +mod date; +mod models; +mod buf; +mod db; +use crate::db::PgConnection; +use crate::date::get_date_fast; +const URL:&'static str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; +// const URL:&'static str = "postgres://postgres:root@localhost:5432/techmpower"; + +const PLAINTEXT:&'static [u8] = br#"Hello, World!"#; + +fn main() { + let thread_init = || async { + get_connection().await; + }; + let mut conf = ServerConfigurations::bind("0.0.0.0", 8080); + conf.max_cached_buffers_count = 2500; + conf.default_write_buffer_size = conf.default_read_buffer_size * 2; + conf.max_buffer_size_for_cache = conf.default_write_buffer_size; + serve::<16, 10, _,_,_>(conf, HandlerFn(|ctx: CtxPtr<16, 10>| handler(ctx)),Some(thread_init)); +} + +async fn handler(mut ctx: CtxPtr<16,10>){ + let ctx = ctx.get(); + let req = ctx.request(); + + let path = req.path(); + match path { + "/plaintext"=>{ + ctx.set_header("Content-Type","text/plain; charset=utf-8"); + ctx.set_header("Content-Length",PLAINTEXT.len()); + ctx.set_header("Server","W"); + ctx.set_header("Date",get_date_fast()); + ctx.write_body_bytes(PLAINTEXT); + } + "/json" =>{ + let js = models::JsonHolder{message:"Hello, World!"}; + let mut buffer = buf::PooledBuffer::new().take_inner(); + _=sonic_rs::to_writer(&mut buffer,&js); + ctx.set_header("Content-Type","application/json"); + ctx.set_header("Content-Length",buffer.len()); + ctx.set_header("Server","W"); + ctx.set_header("Date",get_date_fast()); + ctx.write_body_bytes(&buffer); + buf::PooledBuffer::recycle(buffer) + } + + "/fortunes"=>{ + let connection = get_connection().await; + let fortunes = connection.tell_fortune().await.unwrap(); + ctx.set_header("Content-Type","text/html; charset=UTF-8"); + ctx.set_header("Server","W"); + ctx.set_header("Date",get_date_fast()); + ctx.set_header("Content-Length",fortunes.len()); + ctx.write_body_bytes(&fortunes); + FortunesPool::save_heap_allocation(fortunes); + } + + "/db" => { + let connection = get_connection().await; + let db = connection.get_world().await; + ctx.set_header("Content-Type","application/json"); + ctx.set_header("Server","W"); + ctx.set_header("Date",get_date_fast()); + ctx.set_header("Content-Length",db.len()); + ctx.write_body_bytes(&db); + PooledBuffer::recycle(db); + } + + _=>{ + if path.contains("?") { + let value = path.split("=").last() + .and_then(|v| v.parse::().ok()) + .unwrap_or(1) + .clamp(1, 500); + let s =&path[0..=1]; + match s { + "/q"=>{ + let q = get_connection().await; + let data = q.get_worlds(value).await; + ctx.set_header("Content-Type","application/json"); + ctx.set_header("Server","W"); + ctx.set_header("Date",get_date_fast()); + ctx.set_header("Content-Length",data.len()); + ctx.write_body_bytes(&data); + PooledBuffer::recycle(data); + return + } + "/u"=> { + let q = get_connection().await; + let data = q.update(value).await; + ctx.set_header("Content-Type","application/json"); + ctx.set_header("Server","W"); + ctx.set_header("Date",get_date_fast()); + ctx.set_header("Content-Length",data.len()); + ctx.write_body_bytes(&data); + PooledBuffer::recycle(data); + return + } + _=>{} + } + + } + ctx.set_status_code(HttpStatusCode::NOT_FOUND); + } + } + +} + + +thread_local! { + static PG:OnceCell = OnceCell::new(); +} + +async fn get_connection() -> &'static PgConnection { + // 1. Try to get the pointer from thread-local + let ptr = PG.with(|cell| { + cell.get().map(|conn| conn as *const PgConnection) + }); + + if let Some(p) = ptr { + // SAFETY: We are promoting a thread-local pointer to 'static. + // This is only safe in TFB if the thread never dies. + return unsafe { &*p }; + } + + let mut t_count = 0_usize; + // 2. Initialize + let conn = loop { + match PgConnection::connect(URL) + .await { + Ok(r) => { + break r + } + Err(_) => { + t_count+=1; + println!("failed count = {t_count}"); + if t_count > 10 { + panic!("could not connect to db"); + } + continue } + } + }; + println!("{:?} connected successfully", std::thread::current().name().unwrap()); + // 3. Store it + PG.with(|cell| { + _= cell.set(conn); + }); + + // 4. Retrieve the pointer again + let ptr = PG.with(|cell| { + cell.get().map(|conn| conn as *const PgConnection) + }).expect("Should be initialized"); + + unsafe { &*ptr } +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/models.rs b/frameworks/Rust/water-http/src/models.rs index 1fee7283ba9..d1e008cc589 100644 --- a/frameworks/Rust/water-http/src/models.rs +++ b/frameworks/Rust/water-http/src/models.rs @@ -17,6 +17,10 @@ pub struct Fortune { pub struct FortuneTemplate<'a>{ pub items:&'a Vec } +#[derive(Serialize,Debug)] +pub struct JsonHolder { + pub message:&'static str +} diff --git a/frameworks/Rust/water-http/src/plaintext.rs b/frameworks/Rust/water-http/src/plaintext.rs deleted file mode 100644 index 197da216e9c..00000000000 --- a/frameworks/Rust/water-http/src/plaintext.rs +++ /dev/null @@ -1,54 +0,0 @@ -use water_http::{InitControllersRoot, RunServer, WaterController}; -use water_http::server::ServerConfigurations; - -InitControllersRoot! { - name:ROOT, - holder_type:MainType, -} - - - -pub type MainType = u8; - - -fn main() { - run_server(); -} - - -pub fn run_server(){ - - let cpu_nums = num_cpus::get(); - - - println!("start listening on port 8080 while workers count {cpu_nums}"); - let mut conf = ServerConfigurations::bind("0.0.0.0",8080); - conf.worker_threads_count = cpu_nums * 1 ; - - RunServer!( - conf, - ROOT, - EntryController - ); -} - -const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; -const P:&'static [u8] = br#"Hello, World!"#; - - -WaterController! { - holder -> super::MainType, - name -> EntryController, - functions -> { - - GET => plaintext => p(cx) { - let mut sender = cx.sender(); - sender.set_header_ef("Content-Type","text/plain; charset=utf-8"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _=sender.send_data_as_final_response(http::ResponseData::Str("Hello, World!")).await; - } - } -} - diff --git a/frameworks/Rust/water-http/src/server.rs b/frameworks/Rust/water-http/src/server.rs index be464a0e3d6..b2ce34241df 100644 --- a/frameworks/Rust/water-http/src/server.rs +++ b/frameworks/Rust/water-http/src/server.rs @@ -36,10 +36,9 @@ pub fn run_server(){ conf.worker_threads_count = cpu_nums * 1 ; } - // let addresses = (0..cpu_nums).map(|_| { - // ("0.0.0.0".to_string(),8080) - // }).collect::>(); - // conf.addresses = addresses; + conf.max_cached_buffers_count = 2500; + conf.default_write_buffer_size = conf.default_read_buffer_size * 2; + conf.max_buffer_size_for_cache = conf.default_write_buffer_size; RunServer!( conf, ROOT, @@ -66,12 +65,12 @@ fn shared_factory()->Pin>>{ }) } -#[cfg(any(feature = "json_plaintext",feature = "all"))] -const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; -#[cfg(any(feature = "json_plaintext",feature = "all"))] + +#[cfg(any(feature = "json_plaintext",feature = "all",feature = "uring"))] const P:&'static [u8] = br#"Hello, World!"#; -#[cfg(feature = "all")] + +#[cfg(any(feature = "all",feature = "uring"))] WaterController! { holder -> super::MainType, shared -> super::SharedType, @@ -83,9 +82,12 @@ WaterController! { let mut sender = cx.sender(); sender.set_header_ef("Content-Type","application/json"); sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _=sender.send_data_as_final_response(http::ResponseData::Slice(super::JSON_RESPONSE)).await; + let js = crate::models::JsonHolder{message:"Hello, World!"}; + let mut buffer = crate::buf::PooledBuffer::new().take_inner(); + _=sonic_rs::to_writer(&mut buffer,&js); + sender.set_header_ef("Date",crate::date::get_date_fast()); + _=sender.send_data_as_final_response(http::ResponseData::Slice(&buffer)).await; + crate::buf::PooledBuffer::recycle(buffer); } GET => plaintext => p(cx){ @@ -105,11 +107,11 @@ WaterController! { let mut sender = context.sender(); sender.set_header_ef("Content-Type","application/json"); sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); + sender.set_header_ef("Date",crate::date::get_date_fast()); _= sender.send_data_as_final_response( - http::ResponseData::Slice(data) + http::ResponseData::Slice(&data) ).await; + crate::buf::PooledBuffer::recycle(data); } GET -> queries -> query (context){ let q = context @@ -124,11 +126,11 @@ WaterController! { let mut sender = context.sender(); sender.set_header_ef("Content-Type","application/json"); sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); + sender.set_header_ef("Date",crate::date::get_date_fast()); _= sender.send_data_as_final_response( - http::ResponseData::Slice(data) + http::ResponseData::Slice(&data) ).await; + crate::buf::PooledBuffer::recycle(data); } GET -> updates -> update (context){ @@ -143,11 +145,11 @@ WaterController! { let mut sender = context.sender(); sender.set_header_ef("Content-Type","application/json"); sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); + sender.set_header_ef("Date",crate::date::get_date_fast()); _= sender.send_data_as_final_response( - http::ResponseData::Slice(data) + http::ResponseData::Slice(&data) ).await; + crate::buf::PooledBuffer::recycle(data); } @@ -164,127 +166,16 @@ WaterController! { }; let mut sender = context.sender(); sender.set_header_ef("Content-Type","text/html; charset=UTF-8"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); + sender.set_header_ef("Server","W"); + // let date = httpdate::fmt_http_date(std::time::SystemTime::now()); + sender.set_header_ef("Date",crate::date::get_date_fast()); _= sender.send_data_as_final_response( http::ResponseData::Slice(&data) ).await; + crate::buf::PooledBuffer::recycle(data); } } } - -#[cfg(all(not(feature = "all"),feature = "json_plaintext"))] -WaterController! { - holder -> super::MainType, - shared -> super::SharedType, - name -> EntryController, - functions -> { - - - GET => json => j(cx){ - let mut sender = cx.sender(); - sender.set_header_ef("Content-Type","application/json"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _=sender.send_data_as_final_response(http::ResponseData::Slice(super::JSON_RESPONSE)).await; - } - - GET => plaintext => p(cx) { - let mut sender = cx.sender(); - sender.set_header_ef("Content-Type","text/plain; charset=utf-8"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _=sender.send_data_as_final_response(http::ResponseData::Slice(super::P)).await; - } - } -} - -#[cfg(all(not(feature = "all"),feature = "db"))] -WaterController! { - holder -> super::MainType, - shared -> super::SharedType, - name -> EntryController, - functions -> { - - - GET -> db -> db (context){ - let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); - let connection = connection.pg_connection.get_connection(); - let data = connection.get_world().await; - let mut sender = context.sender(); - sender.set_header_ef("Content-Type","application/json"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _= sender.send_data_as_final_response( - http::ResponseData::Slice(data) - ).await; - } - GET -> queries -> query (context){ - let q = context - .get_from_path_query("q") - .and_then(|v| v.parse::().ok()) // safely parse - .unwrap_or(1) // default to 1 if missing or invalid - .clamp(1, 500); - - let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); - let connection = connection.pg_connection.get_connection(); - let data = connection.get_worlds(q).await; - let mut sender = context.sender(); - sender.set_header_ef("Content-Type","application/json"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _= sender.send_data_as_final_response( - http::ResponseData::Slice(data) - ).await; - } - - GET -> updates -> update (context){ - let q = context - .get_from_path_query("q") - .and_then(|v| v.parse::().ok()) // safely parse - .unwrap_or(1) // default to 1 if missing or invalid - .clamp(1, 500); - let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); - let connection = connection.pg_connection.get_connection(); - let data = connection.update(q).await; - let mut sender = context.sender(); - sender.set_header_ef("Content-Type","application/json"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _= sender.send_data_as_final_response( - http::ResponseData::Slice(data) - ).await; - } - - - GET -> fortunes -> ft (context){ - - let connection:Shared = context.thread_shared_struct.clone().unwrap().clone(); - let connection = connection.pg_connection.get_connection(); - let data = match connection.tell_fortune().await { - Ok(r)=>{r}, - _=>{ - _= context.send_str("failed to connect").await; - return - } - }; - let mut sender = context.sender(); - sender.set_header_ef("Content-Type","text/html; charset=UTF-8"); - sender.set_header_ef("Server","water"); - let date = httpdate::fmt_http_date(std::time::SystemTime::now()); - sender.set_header_ef("Date",date); - _= sender.send_data_as_final_response( - http::ResponseData::Slice(&data) - ).await; - } - } -} \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-cached.dockerfile b/frameworks/Rust/water-http/water-http-cached.dockerfile deleted file mode 100644 index 3c873c71520..00000000000 --- a/frameworks/Rust/water-http/water-http-cached.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:latest - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /water -WORKDIR /water - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin cache --features cache - -EXPOSE 8080 - -CMD ./target/release/cache \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-db.dockerfile b/frameworks/Rust/water-http/water-http-db.dockerfile deleted file mode 100644 index 01d9507b35f..00000000000 --- a/frameworks/Rust/water-http/water-http-db.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:latest - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /water -WORKDIR /water - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin water-http --features db - -EXPOSE 8080 - -CMD ./target/release/water-http \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-json.dockerfile b/frameworks/Rust/water-http/water-http-json.dockerfile deleted file mode 100644 index 4c457496cec..00000000000 --- a/frameworks/Rust/water-http/water-http-json.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:latest - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /water -WORKDIR /water - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin json --features json_plaintext - -EXPOSE 8080 - -CMD ./target/release/json \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-mini.dockerfile b/frameworks/Rust/water-http/water-http-mini.dockerfile new file mode 100644 index 00000000000..7acbcec530f --- /dev/null +++ b/frameworks/Rust/water-http/water-http-mini.dockerfile @@ -0,0 +1,13 @@ +FROM rust:1.93 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +WORKDIR /water +COPY . . + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release --bin mini --features mini + +EXPOSE 8080 + +CMD ./target/release/mini \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-plaintext.dockerfile b/frameworks/Rust/water-http/water-http-plaintext.dockerfile deleted file mode 100644 index ab53eb54496..00000000000 --- a/frameworks/Rust/water-http/water-http-plaintext.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:latest - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /water -WORKDIR /water - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin plaintext --features json_plaintext - -EXPOSE 8080 - -CMD ./target/release/plaintext \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-tokio.dockerfile b/frameworks/Rust/water-http/water-http-tokio.dockerfile new file mode 100644 index 00000000000..a5f3fc1401d --- /dev/null +++ b/frameworks/Rust/water-http/water-http-tokio.dockerfile @@ -0,0 +1,13 @@ +FROM rust:1.93 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +WORKDIR /water +COPY . . + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native --cfg tokio_unstable" cargo build --release --bin water-http --features all + +EXPOSE 8080 + +CMD ./target/release/water-http \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http-uring.dockerfile b/frameworks/Rust/water-http/water-http-uring.dockerfile new file mode 100644 index 00000000000..50d5a991f6a --- /dev/null +++ b/frameworks/Rust/water-http/water-http-uring.dockerfile @@ -0,0 +1,13 @@ +FROM rust:1.93 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +WORKDIR /water +COPY . . + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin water-http --features uring + +EXPOSE 8080 + +CMD ./target/release/water-http \ No newline at end of file diff --git a/frameworks/Rust/water-http/water-http.dockerfile b/frameworks/Rust/water-http/water-http.dockerfile index 5946c8b3821..176ebaf8cfd 100644 --- a/frameworks/Rust/water-http/water-http.dockerfile +++ b/frameworks/Rust/water-http/water-http.dockerfile @@ -1,9 +1,9 @@ -FROM rust:latest +FROM rust:1.93 RUN apt-get update -yqq && apt-get install -yqq cmake g++ -ADD ./ /water WORKDIR /water +COPY . . RUN cargo clean RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin water-http --features all diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock old mode 100755 new mode 100644 index 395d9b82907..1761e7c13ce --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -24,11 +24,57 @@ dependencies = [ "memchr", ] +[[package]] +name = "annotate-snippets" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86cd1c51b95d71dde52bca69ed225008f6ff4c8cc825b08042aa1ef823e1980" +dependencies = [ + "anstyle", + "memchr", + "unicode-width", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "assert-struct" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "3c3b55e0f439cee96bdc160bd46c243c44031cf062013d90d8e37ff00fc4cfa3" +dependencies = [ + "annotate-snippets", + "assert-struct-macros", + "regex", +] + +[[package]] +name = "assert-struct-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb915d95f1988c3279448cfecc14eb93f11ea97a9b9bb97079793ee9a24ac4d" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] [[package]] name = "async-stream" @@ -52,6 +98,12 @@ dependencies = [ "syn", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.89" @@ -101,9 +153,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -116,9 +168,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "by_address" @@ -134,15 +186,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.49" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -154,6 +206,151 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "compio" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a7cc183295c36483f1c9616f43c4ac1a9030ce6d9321d6cebb4c4bb21164c4" +dependencies = [ + "compio-buf", + "compio-driver", + "compio-fs", + "compio-io", + "compio-log", + "compio-net", + "compio-runtime", +] + +[[package]] +name = "compio-buf" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ebb4036bf394915196c09362e4fd5581ee8bf0f3302ab598bff9d646aea2061" +dependencies = [ + "arrayvec", + "bytes", + "libc", +] + +[[package]] +name = "compio-driver" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff5c12800e82a01d12046ccc29b014e1cbbb2fbe38c52534e0d40d4fc58881d5" +dependencies = [ + "cfg-if", + "cfg_aliases", + "compio-buf", + "compio-log", + "crossbeam-queue", + "flume", + "futures-util", + "io-uring", + "io_uring_buf_ring", + "libc", + "once_cell", + "paste", + "polling", + "slab", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-fs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c568022f90c2e2e8ea7ff4c4e8fde500753b5b9b6b6d870e25b5e656f9ea2892" +dependencies = [ + "cfg-if", + "cfg_aliases", + "compio-buf", + "compio-driver", + "compio-io", + "compio-runtime", + "libc", + "os_pipe", + "widestring", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-io" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1e64c6d723589492a4f5041394301e9903466a606f6d9bcc11e406f9f07e9ec" +dependencies = [ + "compio-buf", + "futures-util", + "paste", +] + +[[package]] +name = "compio-log" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4e560213c1996b618da369b7c9109564b41af9033802ae534465c4ee4e132f" +dependencies = [ + "tracing", +] + +[[package]] +name = "compio-net" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffab78b8a876111ca76450912ca6a5a164b0dd93973e342c5f438a6f478c735" +dependencies = [ + "cfg-if", + "compio-buf", + "compio-driver", + "compio-io", + "compio-runtime", + "either", + "libc", + "once_cell", + "socket2", + "widestring", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-runtime" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fd890a129a8086af857bbe18401689c130aa6ccfc7f3c029a7800f7256af3e" +dependencies = [ + "async-task", + "cfg-if", + "compio-buf", + "compio-driver", + "compio-log", + "core_affinity", + "crossbeam-queue", + "futures-util", + "libc", + "once_cell", + "pin-project-lite", + "scoped-tls", + "slab", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "core_affinity" version = "0.8.3" @@ -174,6 +371,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crypto-common" version = "0.1.7" @@ -219,11 +431,32 @@ dependencies = [ "syn", ] +[[package]] +name = "deadpool" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +dependencies = [ + "deadpool-runtime", + "lazy_static", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + [[package]] name = "diesel" -version = "2.3.4" +version = "2.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c415189028b232660655e4893e8bc25ca7aee8e96888db66d9edb400535456a" +checksum = "d9b6c2fc184a6fb6ebcf5f9a5e3bbfa84d8fd268cdfcce4ed508979a6259494d" dependencies = [ "bitflags", "byteorder", @@ -233,23 +466,11 @@ dependencies = [ "pq-sys", ] -[[package]] -name = "diesel-async" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13096fb8dae53f2d411c4b523bec85f45552ed3044a2ab4d85fb2092d9cb4f34" -dependencies = [ - "diesel", - "futures-core", - "futures-util", - "scoped-futures", -] - [[package]] name = "diesel_derives" -version = "2.3.5" +version = "2.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8587cbca3c929fb198e7950d761d31ca72b80aa6e07c1b7bec5879d187720436" +checksum = "47618bf0fac06bb670c036e48404c26a865e6a71af4114dfd97dfe89936e404e" dependencies = [ "diesel_table_macro_syntax", "dsl_auto_type", @@ -321,6 +542,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -329,9 +560,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "faststr" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baec6a0289d7f1fe5665586ef7340af82e3037207bef60f5785e57569776f0c8" +checksum = "1ca7d44d22004409a61c393afb3369c8f7bb74abcae49fe249ee01dcc3002113" dependencies = [ "bytes", "rkyv", @@ -341,9 +572,18 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "spin", +] [[package]] name = "fnv" @@ -351,6 +591,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -362,33 +608,45 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-macro" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", + "futures-macro", "futures-sink", "futures-task", "pin-project-lite", - "pin-utils", + "slab", ] [[package]] @@ -403,9 +661,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", @@ -424,11 +682,28 @@ dependencies = [ "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.0", + "wasip2", + "wasip3", +] + [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] [[package]] name = "hashbrown" @@ -527,9 +802,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -541,9 +816,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -560,6 +835,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -595,12 +876,14 @@ checksum = "44faf5bb8861a9c72e20d3fb0fdbd59233e43056e2b80475ab0aacdc2e781355" [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -614,11 +897,22 @@ dependencies = [ "libc", ] +[[package]] +name = "io_uring_buf_ring" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1838759bb8c2f24cf05a35429d83145c4aa6af43f8ad38477295e12a7320a80e" +dependencies = [ + "bytes", + "io-uring", + "rustix", +] + [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "itoap" @@ -628,9 +922,9 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -642,11 +936,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.178" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libmimalloc-sys" @@ -658,6 +958,12 @@ dependencies = [ "libc", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "litemap" version = "0.8.1" @@ -673,6 +979,18 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" + [[package]] name = "md-5" version = "0.10.6" @@ -685,9 +1003,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mimalloc" @@ -754,6 +1072,16 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "parking_lot" version = "0.12.5" @@ -777,6 +1105,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.2" @@ -785,15 +1119,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" @@ -811,11 +1139,25 @@ dependencies = [ "regex", ] +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "postgres-protocol" -version = "0.6.9" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" +checksum = "3ee9dd5fe15055d2b6806f4736aa0c9637217074e224bbec46d4041b91bb9491" dependencies = [ "base64", "byteorder", @@ -831,13 +1173,14 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" +checksum = "54b858f82211e84682fecd373f68e1ceae642d8d751a1ebd13f33de6257b3e20" dependencies = [ "bytes", "fallible-iterator", "postgres-protocol", + "uuid", ] [[package]] @@ -869,11 +1212,21 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -900,9 +1253,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -940,7 +1293,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "getrandom 0.4.1", + "rand_core 0.10.0", ] [[package]] @@ -960,7 +1323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -969,18 +1332,24 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1012,9 +1381,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1024,9 +1393,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1035,9 +1404,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rend" @@ -1047,12 +1416,12 @@ checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" [[package]] name = "rkyv" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4" +checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70" dependencies = [ "bytes", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "indexmap", "munge", "ptr_meta", @@ -1065,15 +1434,28 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482" +checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1082,9 +1464,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "sailfish" @@ -1098,13 +1480,10 @@ dependencies = [ ] [[package]] -name = "scoped-futures" -version = "0.1.4" +name = "scoped-tls" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091" -dependencies = [ - "pin-project-lite", -] +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" @@ -1112,6 +1491,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1144,15 +1529,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -1186,10 +1571,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -1201,9 +1587,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -1213,9 +1599,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -1223,18 +1609,18 @@ dependencies = [ [[package]] name = "sonic-number" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a74044c092f4f43ca7a6cfd62854cf9fb5ac8502b131347c990bf22bef1dfe" +checksum = "5661364b38abad49cf1ade6631fcc35d2ccf882a7d68616b4228b7717feb5fba" dependencies = [ "cfg-if", ] [[package]] name = "sonic-rs" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4425ea8d66ec950e0a8f2ef52c766cc3d68d661d9a0845c353c40833179fd866" +checksum = "e16b39f36452a4fa6f14a481b02e9ba5c6842c6a44d0545da967eca122f2eed9" dependencies = [ "ahash", "bumpalo", @@ -1243,23 +1629,32 @@ dependencies = [ "faststr", "itoa", "ref-cast", - "ryu", "serde", "simdutf8", "sonic-number", "sonic-simd", "thiserror", + "zmij", ] [[package]] name = "sonic-simd" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5707edbfb34a40c9f2a55fa09a49101d9fec4e0cc171ce386086bd9616f34257" +checksum = "e9f944718c33623919878cf74b4c9361eb3024f635733922b26722b14cd3f8cc" dependencies = [ "cfg-if", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1269,7 +1664,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "std-util" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" +source = "git+https://github.com/fakeshadow/toasty?rev=00dc842#00dc842efe34bfebdc7b0d07028bb4450c3a005b" dependencies = [ "heck", "pluralizer", @@ -1301,9 +1696,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.111" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1323,18 +1718,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1369,11 +1764,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toasty" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" +source = "git+https://github.com/fakeshadow/toasty?rev=00dc842#00dc842efe34bfebdc7b0d07028bb4450c3a005b" dependencies = [ - "anyhow", "async-stream", + "bit-set", "by_address", + "deadpool", "index_vec", "indexmap", "toasty-core", @@ -1387,7 +1783,7 @@ dependencies = [ [[package]] name = "toasty-codegen" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" +source = "git+https://github.com/fakeshadow/toasty?rev=00dc842#00dc842efe34bfebdc7b0d07028bb4450c3a005b" dependencies = [ "proc-macro2", "quote", @@ -1398,9 +1794,9 @@ dependencies = [ [[package]] name = "toasty-core" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" +source = "git+https://github.com/fakeshadow/toasty?rev=00dc842#00dc842efe34bfebdc7b0d07028bb4450c3a005b" dependencies = [ - "anyhow", + "assert-struct", "async-trait", "bit-set", "indexmap", @@ -1412,7 +1808,7 @@ dependencies = [ [[package]] name = "toasty-macros" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" +source = "git+https://github.com/fakeshadow/toasty?rev=00dc842#00dc842efe34bfebdc7b0d07028bb4450c3a005b" dependencies = [ "proc-macro2", "quote", @@ -1424,17 +1820,16 @@ dependencies = [ [[package]] name = "toasty-sql" version = "0.1.0" -source = "git+https://github.com/fakeshadow/toasty?branch=engine#2132c89dfd7a4698cdaaa85888c016b97c01471a" +source = "git+https://github.com/fakeshadow/toasty?rev=00dc842#00dc842efe34bfebdc7b0d07028bb4450c3a005b" dependencies = [ - "anyhow", "toasty-core", ] [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", @@ -1460,9 +1855,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -1470,9 +1865,10 @@ dependencies = [ ] [[package]] -name = "tokio-uring" -version = "0.5.1" -source = "git+http://github.com/fakeshadow/tokio-uring?rev=97d9a98#97d9a988704b5466809633b3ca6ba07acba3f38b" +name = "tokio-uring-xitca" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51113468aadc91bb484bcd63c785c2ed2d50104d41d48039d0ac9ee25b6a6d4e" dependencies = [ "bytes", "io-uring", @@ -1484,9 +1880,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-core", @@ -1494,9 +1890,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" [[package]] name = "typenum" @@ -1512,9 +1908,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -1531,11 +1927,23 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -1551,11 +1959,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.19.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.1", "js-sys", "rand 0.9.2", "wasm-bindgen", @@ -1581,18 +1989,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -1603,9 +2020,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1613,9 +2030,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -1626,13 +2043,53 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + [[package]] name = "winapi" version = "0.3.9" @@ -1746,9 +2203,91 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -1759,7 +2298,8 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xitca-codegen" version = "0.4.0" -source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc921afd144bf419038845eba96c19949953d7c041018b12fb984c1a0c85bcce" dependencies = [ "quote", "syn", @@ -1767,9 +2307,13 @@ dependencies = [ [[package]] name = "xitca-http" -version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba51754e98a98549a1bae7a2f4c20e6b71d931cee6f43acd0307c2c70ba83f2a" dependencies = [ + "compio-buf", + "compio-io", + "compio-net", "futures-core", "http", "httparse", @@ -1778,7 +2322,6 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tokio-uring", "tracing", "xitca-io", "xitca-router", @@ -1788,23 +2331,43 @@ dependencies = [ [[package]] name = "xitca-io" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b91b7a5ff9e3bed167b7e3bcc7b4462d2cb16d05e3ae913dbc384e463fdd7f" +checksum = "1bf2806223b57d14035c3ef09b02c2b15f5c16def43620353e5af8985ec94c40" dependencies = [ "bytes", "tokio", - "tokio-uring", + "tokio-uring-xitca", "xitca-unsafe-collection", ] [[package]] name = "xitca-postgres" -version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2f5b49f1f9af38063a5f06c92d0cb152ef482b8c60da4744372093d8c8b786" dependencies = [ "fallible-iterator", "futures-core", + "lru", + "percent-encoding", + "postgres-protocol", + "postgres-types", + "tokio", + "tracing", + "xitca-io", + "xitca-unsafe-collection", +] + +[[package]] +name = "xitca-postgres" +version = "0.5.0" +source = "git+http://github.com/HFQR/xitca-web?rev=bd86c7c#bd86c7c1187836e27acc00e5e6eb8c6f6a041123" +dependencies = [ + "compio", + "fallible-iterator", + "futures-core", + "lru", "percent-encoding", "postgres-protocol", "postgres-types", @@ -1816,49 +2379,46 @@ dependencies = [ [[package]] name = "xitca-postgres-diesel" -version = "0.2.0" -source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=fb5dcba#fb5dcba5a89164a880a3e82d62dcb3ae5e99ae6e" +version = "0.3.0" +source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=b52805d#b52805d5113455b978293512645ac137bcec1ee3" dependencies = [ "diesel", - "diesel-async", - "futures-util", - "scoped-futures", "tokio", - "xitca-postgres", + "xitca-postgres 0.4.0", ] [[package]] name = "xitca-postgres-toasty" version = "0.1.0" -source = "git+https://github.com/fakeshadow/xitca-postgres-toasty?rev=04bedb8#04bedb8641a13b61f13c85a1fd0b8318dd5454a8" +source = "git+https://github.com/fakeshadow/xitca-postgres-toasty?rev=2b17c07#2b17c07d6b6315cc4cd2111e831e5d0ea7291b2c" dependencies = [ - "anyhow", + "async-stream", "futures-core", - "pin-project-lite", "postgres-types", "toasty-core", "toasty-sql", "tokio", - "xitca-postgres", + "uuid", + "xitca-postgres 0.4.0", ] [[package]] name = "xitca-router" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a771113f381c9a2f5ae1096b70d629ed241a1a473304ea902258c3d528f536" +version = "0.4.1" +source = "git+http://github.com/HFQR/xitca-web?rev=bd86c7c#bd86c7c1187836e27acc00e5e6eb8c6f6a041123" dependencies = [ "xitca-unsafe-collection", ] [[package]] name = "xitca-server" -version = "0.5.0" -source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94cbf5013af573c362caebeba0e2b6c62ebecc121ab24e3fd0523543e490ce8" dependencies = [ "socket2", "tokio", - "tokio-uring", + "tokio-uring-xitca", "tracing", "xitca-io", "xitca-service", @@ -1868,7 +2428,8 @@ dependencies = [ [[package]] name = "xitca-service" version = "0.3.0" -source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f9f7ff163aa7a466a40c6ee92571cbfba705f295bff4412854189454c54ed7" [[package]] name = "xitca-unsafe-collection" @@ -1884,40 +2445,40 @@ name = "xitca-web" version = "0.1.0" dependencies = [ "atoi", + "compio", "core_affinity", "diesel", - "diesel-async", "futures-core", "futures-util", "httparse", "mimalloc", - "rand 0.9.2", + "rand 0.10.0", "sailfish", "serde_core", "serde_json", + "socket2", "sonic-rs", "toasty", "tokio", - "tokio-uring", "xitca-http", "xitca-io", - "xitca-postgres", + "xitca-postgres 0.5.0", "xitca-postgres-diesel", "xitca-postgres-toasty", "xitca-server", "xitca-service", "xitca-unsafe-collection", - "xitca-web 0.7.1", + "xitca-web 0.8.0", ] [[package]] name = "xitca-web" -version = "0.7.1" -source = "git+http://github.com/HFQR/xitca-web?rev=83b4a60#83b4a607a9a704a4286dd190209e567316589afc" +version = "0.8.0" +source = "git+http://github.com/HFQR/xitca-web?rev=bd86c7c#bd86c7c1187836e27acc00e5e6eb8c6f6a041123" dependencies = [ "futures-core", "pin-project-lite", - "serde", + "serde_core", "serde_json", "serde_urlencoded", "tokio", @@ -1953,18 +2514,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", @@ -2024,3 +2585,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml old mode 100755 new mode 100644 index 153519e5575..cc5d9c2e1b6 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -6,12 +6,17 @@ edition = "2024" [[bin]] name = "xitca-web" path = "./src/main.rs" -required-features = ["io-uring", "json", "pg", "router", "template"] +required-features = ["io-uring", "pg", "router", "template", "zero-copy"] + +[[bin]] +name = "xitca-web-compio" +path = "./src/main_compio.rs" +required-features = ["compio", "perf", "perf-json", "pg", "router", "template", "zero-copy"] [[bin]] name = "xitca-web-barebone" path = "./src/main_barebone.rs" -required-features = ["perf", "perf-json", "pg", "template"] +required-features = ["perf", "perf-json", "pg", "template", "zero-copy"] [[bin]] name = "xitca-web-diesel" @@ -27,30 +32,33 @@ required-features = ["perf", "template", "toasty", "web-codegen"] # pg client optional pg = ["dep:xitca-postgres"] # diesel orm optional -diesel = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"] +diesel = ["dep:diesel", "dep:xitca-postgres-diesel", "futures-util/alloc"] # toasty orm optional toasty = ["dep:toasty", "dep:xitca-postgres-toasty", "futures-util/alloc"] # http router optional router = ["xitca-http/router"] -# web optional -web = ["dep:xitca-web"] # web with macros optional web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"] # template optional template = ["dep:sailfish"] # io-uring optional -io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"] +io-uring = ["xitca-http/io-uring", "xitca-server/io-uring"] +# zero-copy database row parsing optional(not supported by ORMs) +zero-copy = [] # unrealistic performance optimization -perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot"] +perf = ["perf-allocator", "dep:core_affinity", "tokio/parking_lot"] +perf-allocator = ["dep:mimalloc"] # regular json serializer json = ["serde_json"] # performance optimization json serializer perf-json = ["sonic-rs"] +# compio as runtime +compio = ["dep:compio", "dep:socket2", "xitca-http/compio", "xitca-postgres/compio"] [dependencies] -xitca-http = "0.7" -xitca-io = "0.4.1" -xitca-server = "0.5" +xitca-http = "0.8.2" +xitca-io = "0.5.1" +xitca-server = "0.6.1" xitca-service = "0.3" xitca-unsafe-collection = "0.2" @@ -59,27 +67,23 @@ httparse = "1" serde_core = { version = "1" } # web optional -xitca-web = { version = "0.7", features = ["json"], optional = true } +xitca-web = { version = "0.8", features = ["json"], optional = true } # raw-pg optional -xitca-postgres = { version = "0.3", optional = true } +xitca-postgres = { version = "0.5.0", optional = true } # diesel orm optional diesel = { version = "2", features = ["postgres"], optional = true } -diesel-async = { version = "0.7", optional = true } -xitca-postgres-diesel = { version = "0.2", default-features = false, optional = true } +xitca-postgres-diesel = { version = "0.3", default-features = false, optional = true } futures-util = { version = "0.3", default-features = false, optional = true } # toasty orm optional -xitca-postgres-toasty = { version = "0.1", optional = true } +xitca-postgres-toasty = { version = "0.1", features = ["nightly"], optional = true } toasty = { version = "0.1", optional = true } # template optional sailfish = { version = "0.10", default-features = false, features = ["perf-inline"], optional = true } -# io-uring optional -tokio-uring = { version = "0.5", optional = true } - # perf optional core_affinity = { version = "0.8.1", optional = true } mimalloc = { version = "0.1", default-features = false, optional = true } @@ -88,8 +92,12 @@ mimalloc = { version = "0.1", default-features = false, optional = true } serde_json = { version = "1", optional = true } sonic-rs = { version = "0.5.6", optional = true } +# compio optional +compio = { version = "0.17", features = ["time"], optional = true } +socket2 = { version = "0.6", optional = true } + futures-core = { version = "0.3", default-features = false } -rand = { version = "0.9", features = ["os_rng", "small_rng"], default-features = false } +rand = { version = "0.10", features = ["sys_rng"], default-features = false } tokio = "1.48" [profile.release] @@ -99,18 +107,13 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "fb5dcba" } -xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "04bedb8" } - -# personal fork for efficient toasty engine fine tuned with pipelined xitca-postgres client -toasty = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } -toasty-core = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } -toasty-sql = { git = "https://github.com/fakeshadow/toasty", branch = "engine" } -tokio-uring = { git = "http://github.com/fakeshadow/tokio-uring", rev = "97d9a98" } - -xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } -xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } -xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } -xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } -xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } -xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "83b4a60" } +xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "b52805d" } +xitca-postgres-toasty = { git = "https://github.com/fakeshadow/xitca-postgres-toasty", rev = "2b17c07" } + +toasty = { git = "https://github.com/fakeshadow/toasty", rev = "00dc842" } +toasty-core = { git = "https://github.com/fakeshadow/toasty", rev = "00dc842" } +toasty-sql = { git = "https://github.com/fakeshadow/toasty", rev = "00dc842" } + +xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "bd86c7c" } +xitca-router = { git = "http://github.com/HFQR/xitca-web", rev = "bd86c7c" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "bd86c7c" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json old mode 100755 new mode 100644 index b1b96249711..a9d457c20ee --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "xitca-web", + "maintainers": ["fakeshadow"], "tests": [ { "default": { @@ -46,6 +47,28 @@ "notes": "", "versus": "" }, + "compio": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "xitca-web", + "language": "Rust", + "orm": "Raw", + "platform": "None", + "webserver": "xitca-server", + "os": "Linux", + "database_os": "Linux", + "display_name": "xitca-web [compio]", + "notes": "", + "versus": "" + }, "diesel": { "db_url": "/db", "fortune_url": "/fortunes", diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 7a380357cd5..aa72fb00076 100755 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,47 +1,57 @@ -#[path = "./db_util.rs"] -mod db_util; - -use xitca_postgres::{Execute, iter::AsyncLendingIterator, pool::Pool}; +use xitca_postgres::{ + Execute, + dev::ClientBorrow, + iter::AsyncLendingIterator, + statement::{Statement, StatementNamed}, + types::Type, +}; -use super::{ +use crate::{ ser::{Fortune, Fortunes, World}, - util::{DB_URL, HandleResult, Rand}, + util::{Error, HandleResult, Rand}, }; -use db_util::{FORTUNE_STMT, UPDATE_STMT, WORLD_STMT, not_found}; - -pub struct Client { - pool: Pool, - rng: core::cell::RefCell, +#[cold] +#[inline(never)] +fn not_found() -> Error { + "request World does not exist".into() } -pub async fn create() -> HandleResult { - Ok(Client { - pool: Pool::builder(DB_URL).capacity(1).build()?, - rng: Default::default(), - }) +#[derive(Default)] +pub struct Exec { + rng: core::cell::RefCell, } -impl Client { - pub async fn get_world(&self) -> HandleResult { - let mut conn = self.pool.get().await?; - let stmt = WORLD_STMT.execute(&mut conn).await?; +impl Exec { + pub const FORTUNE_STMT: StatementNamed<'_> = Statement::named("SELECT id,message FROM fortune", &[]); + pub const WORLD_STMT: StatementNamed<'_> = + Statement::named("SELECT id,randomNumber FROM world WHERE id=$1", &[Type::INT4]); + pub const UPDATE_STMT: StatementNamed<'_> = Statement::named( + "UPDATE world SET randomNumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i", + &[Type::INT4_ARRAY, Type::INT4_ARRAY], + ); + + pub(crate) async fn db(&self, conn: C, stmt: &Statement) -> HandleResult + where + C: ClientBorrow, + { let id = self.rng.borrow_mut().gen_id(); - let mut res = stmt.bind([id]).query(&conn.consume()).await?; + let mut res = stmt.bind([id]).query(conn.borrow_cli_ref()).await?; + drop(conn); let row = res.try_next().await?.ok_or_else(not_found)?; Ok(World::new(row.get(0), row.get(1))) } - pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let mut conn = self.pool.get().await?; - let stmt = WORLD_STMT.execute(&mut conn).await?; - + pub(crate) async fn queries(&self, conn: C, stmt: &Statement, num: u16) -> HandleResult> + where + C: ClientBorrow, + { let get = self .rng .borrow_mut() .gen_multi() .take(num as _) - .map(|id| stmt.bind([id]).query(&conn)) + .map(|id| stmt.bind([id]).query(conn.borrow_cli_ref())) .collect::>(); drop(conn); @@ -57,12 +67,17 @@ impl Client { Ok(worlds) } - pub async fn update(&self, num: u16) -> HandleResult> { - let mut conn = self.pool.get().await?; - let world_stmt = WORLD_STMT.execute(&mut conn).await?; - let update_stmt = UPDATE_STMT.execute(&mut conn).await?; - - let (get, update, worlds) = { + pub(crate) async fn updates( + &self, + conn: C, + world_stmt: &Statement, + update_stmt: &Statement, + num: u16, + ) -> HandleResult> + where + C: ClientBorrow, + { + let (worlds, get, update) = { let mut rng = self.rng.borrow_mut(); let mut ids = rng.gen_multi().take(num as _).collect::>(); ids.sort(); @@ -72,18 +87,20 @@ impl Client { .cloned() .zip(rng.gen_multi()) .map(|(id, rand)| { - let get = world_stmt.bind([id]).query(&conn); + let get = world_stmt.bind([id]).query(conn.borrow_cli_ref()); (get, rand, World::new(id, rand)) }) .collect::<(Vec<_>, Vec<_>, Vec<_>)>(); - let update = update_stmt.bind([&ids, &rngs]).query(&conn.consume()); + let update = update_stmt.bind([&ids, &rngs]).execute(conn.borrow_cli_ref()); + + drop(conn); - (get, update, worlds) + (worlds, get, update) }; - for fut in get { - let _rand = fut.await?.try_next().await?.ok_or_else(not_found)?.get::(1); + for get in get { + let _rand = get.await?.try_next().await?.ok_or_else(not_found)?.get::(1); } update.await?; @@ -91,15 +108,18 @@ impl Client { Ok(worlds) } - pub async fn tell_fortune(&self) -> HandleResult { - let mut fortunes = Vec::with_capacity(16); + pub(crate) async fn fortunes(conn: C, stmt: &Statement) -> HandleResult + where + C: ClientBorrow, + { + let mut res = stmt.query(conn.borrow_cli_ref()).await?; - let mut conn = self.pool.get().await?; - let stmt = FORTUNE_STMT.execute(&mut conn).await?; - let mut res = stmt.query(&conn.consume()).await?; + drop(conn); + + let mut fortunes = Vec::with_capacity(16); while let Some(row) = res.try_next().await? { - fortunes.push(Fortune::new(row.get(0), row.get::(1))); + fortunes.push(Fortune::new(row.get(0), row.get_zc(1))); } Ok(Fortunes::new(fortunes)) diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs index 19231abee85..71efa2d7df2 100755 --- a/frameworks/Rust/xitca-web/src/db_diesel.rs +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -1,7 +1,6 @@ -use diesel::prelude::*; -use diesel_async::{AsyncConnection, RunQueryDsl}; -use futures_util::future::{TryFutureExt, TryJoinAll, try_join}; -use xitca_postgres_diesel::AsyncPgConnection; +use diesel::{ExpressionMethods, QueryDsl}; +use futures_util::future::TryJoinAll; +use xitca_postgres_diesel::{AsyncPgConnection, RunQueryDsl}; use crate::{ ser::{Fortunes, World}, @@ -23,72 +22,52 @@ impl Pool { }) } - pub async fn get_world(&self) -> HandleResult { - { - use schema::world::dsl::*; + pub async fn db(&self) -> HandleResult { + use schema::world::dsl::{id, world}; - let w_id = self.rng.borrow_mut().gen_id(); - world.filter(id.eq(w_id)).first(&mut &self.pool).map_err(Into::into) - } - .await - } - - pub async fn get_worlds(&self, num: u16) -> HandleResult> { - { - use schema::world::dsl::*; - - self.rng - .borrow_mut() - .gen_multi() - .take(num as _) - .map(|w_id| world.filter(id.eq(w_id)).first(&mut &self.pool).map_err(Into::into)) - .collect::>() - } - .await + let w_id = self.rng.borrow_mut().gen_id(); + let w = world.filter(id.eq(w_id)).get_result(&self.pool).await?; + Ok(w) } - pub async fn update(&self, num: u16) -> HandleResult> { - { - use schema::world::dsl::*; + pub async fn queries(&self, num: u16) -> HandleResult> { + use schema::world::dsl::{id, world}; - let mut rng = self.rng.borrow_mut(); - let mut params = Vec::with_capacity(num as _); + let get = self + .rng + .borrow_mut() + .gen_multi() + .take(num as _) + .map(|w_id| world.filter(id.eq(w_id)).get_result(&self.pool)) + .collect::>(); - let get = rng - .clone() - .gen_multi() - .take(num as _) - .zip(rng.gen_multi()) - .map(|(w_id, rng)| { - let get = world.filter(id.eq(w_id)).first::(&mut &self.pool); + get.await.map_err(Into::into) + } - params.push((w_id, rng)); + pub async fn updates(&self, num: u16) -> HandleResult> { + let mut worlds = self.queries(num).await?; - async move { - let mut w = get.await?; - w.randomnumber = rng; - HandleResult::Ok(w) - } - }) - .collect::>(); + let params = worlds + .iter_mut() + .zip(self.rng.borrow_mut().gen_multi()) + .map(|(world, rand)| { + world.randomnumber = rand; + (world.id, rand) + }) + .collect(); - let sql = update_query_from_ids(params); - let update = diesel::sql_query(sql).execute(&mut &self.pool).map_err(Into::into); + let sql = update_query_from_ids(params); + diesel::sql_query(sql).execute(&self.pool).await?; - try_join(get, update) - } - .await - .map(|(worlds, _)| worlds) + Ok(worlds) } - pub async fn tell_fortune(&self) -> HandleResult { - { - use schema::fortune::dsl::*; - - fortune.load(&mut &self.pool).map_err(Into::into) - } - .await - .map(Fortunes::new) + pub async fn fortunes(&self) -> HandleResult { + let mut fortunes = Vec::with_capacity(16); + schema::fortune::dsl::fortune + .load_into(&self.pool, &mut fortunes) + .await?; + Ok(Fortunes::new(fortunes)) } } @@ -113,14 +92,28 @@ mod schema { fn update_query_from_ids(mut rngs: Vec<(i32, i32)>) -> String { rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); - const PREFIX: &str = "UPDATE world SET randomNumber=w.r FROM (VALUES "; - const SUFFIX: &str = ") AS w (i,r) WHERE world.id=w.i"; + const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (SELECT unnest(ARRAY["; + const MID: &str = "]) as i, unnest(ARRAY["; + const SUFFIX: &str = "]) as r) w WHERE world.id = w.i"; - let mut query = String::from(PREFIX); + let mut query = String::with_capacity(512); + + query.push_str(PREFIX); use core::fmt::Write; - rngs.iter().for_each(|(w_id, num)| { - write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + + rngs.iter().for_each(|(w_id, _)| { + write!(query, "{},", w_id).unwrap(); + }); + + if query.ends_with(',') { + query.pop(); + } + + query.push_str(MID); + + rngs.iter().for_each(|(_, rand)| { + write!(query, "{},", rand).unwrap(); }); if query.ends_with(',') { diff --git a/frameworks/Rust/xitca-web/src/db_pool.rs b/frameworks/Rust/xitca-web/src/db_pool.rs new file mode 100755 index 00000000000..21e06527a2e --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_pool.rs @@ -0,0 +1,55 @@ +use xitca_postgres::{Execute, pool::Pool}; + +use super::{ + db::Exec, + ser::{Fortunes, World}, + util::{DB_URL, HandleResult}, +}; + +pub struct Client { + pool: Pool, + exec: Exec, +} + +impl Client { + pub async fn create() -> HandleResult { + let mut pool = Pool::builder(DB_URL); + + #[cfg(feature = "compio")] + { + pool = pool.connector(crate::CompIoConnector); + } + + pool = pool.capacity(1); + + Ok(Self { + pool: pool.build()?, + exec: Default::default(), + }) + } + + pub async fn db(&self) -> HandleResult { + let mut conn = self.pool.get().await?; + let stmt = Exec::WORLD_STMT.execute(&mut conn).await?; + self.exec.db(conn, &stmt).await + } + + pub async fn queries(&self, num: u16) -> HandleResult> { + let mut conn = self.pool.get().await?; + let stmt = Exec::WORLD_STMT.execute(&mut conn).await?; + self.exec.queries(conn, &stmt, num).await + } + + pub async fn updates(&self, num: u16) -> HandleResult> { + let mut conn = self.pool.get().await?; + let world_stmt = Exec::WORLD_STMT.execute(&mut conn).await?; + let update_stmt = Exec::UPDATE_STMT.execute(&mut conn).await?; + self.exec.updates(conn, &world_stmt, &update_stmt, num).await + } + + pub async fn fortunes(&self) -> HandleResult { + let mut conn = self.pool.get().await?; + let stmt = Exec::FORTUNE_STMT.execute(&mut conn).await?; + Exec::fortunes(conn, &stmt).await + } +} diff --git a/frameworks/Rust/xitca-web/src/db_toasty.rs b/frameworks/Rust/xitca-web/src/db_toasty.rs index 092f483a61b..6635a79d431 100755 --- a/frameworks/Rust/xitca-web/src/db_toasty.rs +++ b/frameworks/Rust/xitca-web/src/db_toasty.rs @@ -1,4 +1,4 @@ -use futures_util::future::try_join_all; +use futures_util::future::TryJoinAll; use toasty::Db; use crate::{ @@ -13,12 +13,12 @@ pub struct Pool { impl Pool { pub async fn create() -> HandleResult { - let conn = xitca_postgres_toasty::PostgreSQL::connect(DB_URL).await?; + let drv = xitca_postgres_toasty::PostgreSQL::new(DB_URL)?; let db = Db::builder() .register::() .register::() - .build(conn) + .build(drv) .await?; Ok(Self { @@ -27,30 +27,39 @@ impl Pool { }) } - pub async fn get_world(&self) -> HandleResult { + pub async fn db(&self) -> HandleResult { let id = self.rng.borrow_mut().gen_id(); World::get_by_id(&self.db, id).await.map_err(Into::into) } - pub async fn get_worlds(&self, num: u16) -> HandleResult> { - try_join_all(core::iter::repeat_with(|| self.get_world()).take(num as _)).await + pub async fn queries(&self, num: u16) -> HandleResult> { + let get = self + .rng + .borrow_mut() + .gen_multi() + .take(num as _) + .map(|id| World::get_by_id(&self.db, id)) + .collect::>(); + + get.await.map_err(Into::into) } - pub async fn update(&self, num: u16) -> HandleResult> { - let mut worlds = self.get_worlds(num).await?; + pub async fn updates(&self, num: u16) -> HandleResult> { + let mut worlds = self.queries(num).await?; - try_join_all({ - let mut rng = self.rng.borrow_mut(); - worlds - .iter_mut() - .map(move |world| world.update().randomnumber(rng.gen_id()).exec(&self.db)) - }) - .await?; + // TODO: revisit when toasty supports batch update or raw sql + let update = worlds + .iter_mut() + .zip(self.rng.borrow_mut().gen_multi()) + .map(|(world, rand)| world.update().randomnumber(rand).exec(&self.db)) + .collect::>(); + + update.await?; Ok(worlds) } - pub async fn tell_fortune(&self) -> HandleResult { + pub async fn fortunes(&self) -> HandleResult { let fortunes = Fortune::all().all(&self.db).await?.collect().await?; Ok(Fortunes::new(fortunes)) } diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs index 364e020b3b0..7af809089af 100755 --- a/frameworks/Rust/xitca-web/src/db_unrealistic.rs +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -1,114 +1,65 @@ //! this module is unrealistic. related issue: //! https://github.com/TechEmpower/FrameworkBenchmarks/issues/8790 -#[path = "./db_util.rs"] -mod db_util; +use core::future::Future; use xitca_postgres::{Execute, iter::AsyncLendingIterator, statement::Statement}; use super::{ - ser::{Fortune, Fortunes, World}, - util::{DB_URL, HandleResult, Rand}, + db::Exec, + ser::{Fortunes, World}, + util::{DB_URL, HandleResult}, }; -use db_util::{FORTUNE_STMT, UPDATE_STMT, WORLD_STMT, not_found}; - pub struct Client { cli: xitca_postgres::Client, - rng: core::cell::RefCell, + exec: Exec, fortune: Statement, world: Statement, update: Statement, } -pub async fn create() -> HandleResult { - let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?; - - tokio::task::spawn(async move { - while drv.try_next().await?.is_some() {} - HandleResult::Ok(()) - }); - - let world = WORLD_STMT.execute(&cli).await?.leak(); - let fortune = FORTUNE_STMT.execute(&cli).await?.leak(); - let update = UPDATE_STMT.execute(&cli).await?.leak(); - - Ok(Client { - cli, - rng: Default::default(), - world, - fortune, - update, - }) -} - impl Client { - pub async fn get_world(&self) -> HandleResult { - let id = self.rng.borrow_mut().gen_id(); - let mut res = self.world.bind([id]).query(&self.cli).await?; - let row = res.try_next().await?.ok_or_else(not_found)?; - Ok(World::new(row.get(0), row.get(1))) + pub async fn create() -> HandleResult { + let (cli, drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?; + + let mut drv = drv.try_into_tcp().expect("raw tcp is used for database connection"); + + tokio::task::spawn(async move { + while drv.try_next().await?.is_some() {} + HandleResult::Ok(()) + }); + + let world = Exec::WORLD_STMT.execute(&cli).await?.leak(); + let fortune = Exec::FORTUNE_STMT.execute(&cli).await?.leak(); + let update = Exec::UPDATE_STMT.execute(&cli).await?.leak(); + + Ok(Self { + cli, + exec: Default::default(), + world, + fortune, + update, + }) } - pub async fn get_worlds(&self, num: u16) -> HandleResult> { - let get = self - .rng - .borrow_mut() - .gen_multi() - .take(num as _) - .map(|id| self.world.bind([id]).query(&self.cli)) - .collect::>(); - - let mut worlds = Vec::with_capacity(num as _); - - for query in get { - let mut res = query.await?; - let row = res.try_next().await?.ok_or_else(not_found)?; - worlds.push(World::new(row.get(0), row.get(1))); - } - - Ok(worlds) + #[inline] + pub fn db(&self) -> impl Future> { + self.exec.db(&self.cli, &self.world) } - pub async fn update(&self, num: u16) -> HandleResult> { - let (get, update, worlds) = { - let mut rng = self.rng.borrow_mut(); - let mut ids = rng.gen_multi().take(num as _).collect::>(); - ids.sort(); - - let (get, rngs, worlds) = ids - .iter() - .cloned() - .zip(rng.gen_multi()) - .map(|(id, rand)| { - let get = self.world.bind([id]).query(&self.cli); - (get, rand, World::new(id, rand)) - }) - .collect::<(Vec<_>, Vec<_>, Vec<_>)>(); - - let update = self.update.bind([&ids, &rngs]).query(&self.cli); - - (get, update, worlds) - }; - - for fut in get { - let _rand = fut.await?.try_next().await?.ok_or_else(not_found)?.get::(1); - } - - update.await?; - - Ok(worlds) + #[inline] + pub fn queries(&self, num: u16) -> impl Future>> { + self.exec.queries(&self.cli, &self.world, num) } - pub async fn tell_fortune(&self) -> HandleResult { - let mut items = Vec::with_capacity(16); - - let mut res = self.fortune.query(&self.cli).await?; - - while let Some(row) = res.try_next().await? { - items.push(Fortune::new(row.get(0), row.get::(1))); - } + #[inline] + pub fn updates(&self, num: u16) -> impl Future>> { + self.exec.updates(&self.cli, &self.world, &self.update, num) + } - Ok(Fortunes::new(items)) + #[inline] + pub fn fortunes(&self) -> impl Future> { + Exec::fortunes(&self.cli, &self.fortune) } } diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs deleted file mode 100755 index afde4496d9e..00000000000 --- a/frameworks/Rust/xitca-web/src/db_util.rs +++ /dev/null @@ -1,21 +0,0 @@ -use xitca_postgres::{ - statement::{Statement, StatementNamed}, - types::Type, -}; - -use crate::util::Error; - -pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT id,message FROM fortune", &[]); - -pub const WORLD_STMT: StatementNamed = Statement::named("SELECT id,randomnumber FROM world WHERE id=$1", &[Type::INT4]); - -pub const UPDATE_STMT: StatementNamed = Statement::named( - "UPDATE world SET randomnumber=w.r FROM (SELECT unnest($1) as i,unnest($2) as r) w WHERE world.id=w.i", - &[Type::INT4_ARRAY, Type::INT4_ARRAY], -); - -#[cold] -#[inline(never)] -pub fn not_found() -> Error { - "request World does not exist".into() -} diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 30fded2d8d9..7686208c2b2 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -1,11 +1,22 @@ +#[cfg(feature = "perf-allocator")] +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + mod db; +mod db_pool; mod ser; mod util; use xitca_http::{ HttpServiceBuilder, + body::Once, + bytes::Bytes, h1::RequestBody, - http::{StatusCode, header::SERVER}, + http::{ + self, HeaderValue, IntoResponse as _, RequestExt, StatusCode, + const_header_value::{JSON, TEXT_HTML_UTF8, TEXT_UTF8}, + header::{CONTENT_TYPE, SERVER}, + }, util::{ middleware::context::{Context, ContextBuilder}, service::{ @@ -16,63 +27,70 @@ use xitca_http::{ }; use xitca_service::{Service, ServiceExt, fn_service}; -use db::Client; -use ser::{IntoResponse, Message, Request, Response, error_response}; -use util::{QueryParse, SERVER_HEADER_VALUE, State}; +use ser::{HELLO, Message}; +use util::{HandleResult, QueryParse}; + +type Request = http::Request>; + +type Response = http::Response>; -type Ctx<'a> = Context<'a, Request, State>; +type Ctx<'a> = Context<'a, Request, db_pool::Client>; fn main() -> std::io::Result<()> { let service = Router::new() .insert( "/plaintext", - get(fn_service(async |ctx: Ctx| ctx.into_parts().0.text_response())), + get(fn_service(async |ctx: Ctx| { + let (req, _) = ctx.into_parts(); + let mut res = req.into_response(const { Bytes::from_static(HELLO.as_bytes()) }); + res.headers_mut().insert(CONTENT_TYPE, TEXT_UTF8); + Ok(res) + })), ) .insert( "/json", get(fn_service(async |ctx: Ctx| { - let (req, state) = ctx.into_parts(); - req.json_response(state, &Message::new()) + let (req, _) = ctx.into_parts(); + json_response(req, Message::HELLO) })), ) .insert( "/db", get(fn_service(async |ctx: Ctx| { - let (req, state) = ctx.into_parts(); - let world = state.client.get_world().await?; - req.json_response(state, &world) + let (req, cli) = ctx.into_parts(); + cli.db().await.and_then(|w| json_response(req, &w)) })), ) .insert( "/fortunes", get(fn_service(async |ctx: Ctx| { - let (req, state) = ctx.into_parts(); - let fortunes = state.client.tell_fortune().await?.render_once()?; - req.html_response(fortunes) + let (req, cli) = ctx.into_parts(); + let fortunes = cli.fortunes().await?.render_once()?; + let mut res = req.into_response(Bytes::from(fortunes)); + res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8); + Ok(res) })), ) .insert( "/queries", get(fn_service(async |ctx: Ctx| { - let (req, state) = ctx.into_parts(); + let (req, cli) = ctx.into_parts(); let num = req.uri().query().parse_query(); - let worlds = state.client.get_worlds(num).await?; - req.json_response(state, &worlds) + cli.queries(num).await.and_then(|w| json_response(req, &w)) })), ) .insert( "/updates", get(fn_service(async |ctx: Ctx| { - let (req, state) = ctx.into_parts(); + let (req, cli) = ctx.into_parts(); let num = req.uri().query().parse_query(); - let worlds = state.client.update(num).await?; - req.json_response(state, &worlds) + cli.updates(num).await.and_then(|w| json_response(req, &w)) })), ) - .enclosed(ContextBuilder::new(|| async { db::create().await.map(State::new) })) + .enclosed(ContextBuilder::new(db_pool::Client::create)) .enclosed_fn(async |service, req| { let mut res = service.call(req).await.unwrap_or_else(error_handler); - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); + res.headers_mut().insert(SERVER, HeaderValue::from_static("x")); Ok::<_, core::convert::Infallible>(res) }) .enclosed(HttpServiceBuilder::h1().io_uring()); @@ -85,9 +103,23 @@ fn main() -> std::io::Result<()> { #[cold] #[inline(never)] fn error_handler(e: RouterError) -> Response { - error_response(match e { + let status = match e { RouterError::Match(_) => StatusCode::NOT_FOUND, RouterError::NotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED, - RouterError::Service(_) => StatusCode::INTERNAL_SERVER_ERROR, - }) + RouterError::Service(e) => { + eprintln!("Internal Error: {e}"); + StatusCode::INTERNAL_SERVER_ERROR + } + }; + http::Response::builder() + .status(status) + .body(Once::new(Bytes::new())) + .unwrap() +} + +fn json_response(req: Request, val: &impl serde_core::Serialize) -> HandleResult { + let buf = ser::json_serialize(val)?; + let mut res = req.into_response(Bytes::from(buf)); + res.headers_mut().insert(CONTENT_TYPE, JSON); + Ok(res) } diff --git a/frameworks/Rust/xitca-web/src/main_barebone.rs b/frameworks/Rust/xitca-web/src/main_barebone.rs index 8e603ad05e1..1f27eef4c23 100644 --- a/frameworks/Rust/xitca-web/src/main_barebone.rs +++ b/frameworks/Rust/xitca-web/src/main_barebone.rs @@ -5,23 +5,22 @@ #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; -#[path = "db_unrealistic.rs"] mod db; +mod db_unrealistic; mod ser; mod util; use std::io; use xitca_http::{ - bytes::BufMut, h1::dispatcher_unreal::{Dispatcher, Request, Response}, http::StatusCode, }; use xitca_service::Service; use self::{ - ser::Message, - util::{QueryParse, State}, + ser::{HELLO, Message}, + util::QueryParse, }; fn main() -> io::Result<()> { @@ -51,10 +50,10 @@ fn main() -> io::Result<()> { socket.bind(addr)?; let listener = socket.listen(1024)?; - let client = db::create().await.unwrap(); + let client = db_unrealistic::Client::create().await.unwrap(); // unrealistic http dispatcher. no spec check. no security feature. - let service = Dispatcher::new(handler, State::new(client)); + let service = Dispatcher::new(handler, client); loop { match listener.accept().await { @@ -81,74 +80,60 @@ fn main() -> io::Result<()> { // need clean async shutdown will be leaked. worker(ids.pop())?; for handle in handle { - handle.join().unwrap()?; + let _ = handle.join().unwrap(); } Ok(()) } -async fn handler<'h>(req: Request<'h, State>, res: Response<'h>) -> Response<'h, 3> { +async fn handler<'h>(req: Request<'h, db_unrealistic::Client>, res: Response<'h>) -> Response<'h, 3> { // unrealistic due to no http method check match req.path { // unrealistic due to no dynamic path matching "/plaintext" => { // unrealistic due to no body streaming and no post processing. violating middleware feature of xitca-web res.status(StatusCode::OK) + // unrealistic due to no charset k/v pair .header("content-type", "text/plain") .header("server", "X") - // unrealistic content length header. - .header("content-length", "13") - .body_writer(|buf| buf.extend_from_slice(b"Hello, World!")) + .body(HELLO.as_bytes()) } - "/json" => res - .status(StatusCode::OK) - .header("content-type", "application/json") - .header("server", "X") - // unrealistic content length header. - .header("content-length", "27") - // snoic-rs crate is realistic approach to json serializer. - // That said xitca-web by default utilize serde-json as serializer making it an unrealistic representation of framework performance - .body_writer(|buf| sonic_rs::to_writer(buf.writer(), &Message::new()).unwrap()), + "/json" => json_response(res, Message::HELLO), // all database related categories are unrealistic. please reference db_unrealistic module for detail. "/fortunes" => { - let fortunes = req.ctx.client.tell_fortune().await.unwrap().render_once().unwrap(); + // unrealistic due to no error handling. any db/serialization error will cause process crash. + // the same goes for all following unwraps on database related functions. + let fortunes = req.ctx.fortunes().await.unwrap().render_once().unwrap(); res.status(StatusCode::OK) .header("content-type", "text/html; charset=utf-8") .header("server", "X") .body(fortunes.as_bytes()) } "/db" => { - // unrealistic due to no error handling. any db/serialization error will cause process crash. - // the same goes for all following unwraps on database related functions. - let world = req.ctx.client.get_world().await.unwrap(); - json_response(res, req.ctx, &world) + let world = req.ctx.db().await.unwrap(); + json_response(res, &world) } p if p.starts_with("/q") => { let num = p["/queries?q=".len()..].parse_query(); - let worlds = req.ctx.client.get_worlds(num).await.unwrap(); - json_response(res, req.ctx, &worlds) + let worlds = req.ctx.queries(num).await.unwrap(); + json_response(res, &worlds) } p if p.starts_with("/u") => { let num = p["/updates?q=".len()..].parse_query(); - let worlds = req.ctx.client.update(num).await.unwrap(); - json_response(res, req.ctx, &worlds) + let worlds = req.ctx.updates(num).await.unwrap(); + json_response(res, &worlds) } _ => res.status(StatusCode::NOT_FOUND).header("server", "X").body(&[]), } } -fn json_response<'r, DB, T>(res: Response<'r>, state: &State, val: &T) -> Response<'r, 3> -where - T: serde_core::Serialize, -{ - let buf = &mut *state.write_buf.borrow_mut(); - sonic_rs::to_writer(buf.writer(), val).unwrap(); - let res = res - .status(StatusCode::OK) +fn json_response<'r>(res: Response<'r>, val: &impl serde_core::Serialize) -> Response<'r, 3> { + // snoic-rs crate is realistic approach to json serializer. + // That said xitca-web by default utilize serde-json as serializer making it an unrealistic representation of framework performance + let buf = ser::json_serialize(val).unwrap(); + res.status(StatusCode::OK) .header("content-type", "application/json") .header("server", "X") - .body(buf.as_ref()); - buf.clear(); - res + .body(buf.as_ref()) } diff --git a/frameworks/Rust/xitca-web/src/main_compio.rs b/frameworks/Rust/xitca-web/src/main_compio.rs new file mode 100644 index 00000000000..074c687172c --- /dev/null +++ b/frameworks/Rust/xitca-web/src/main_compio.rs @@ -0,0 +1,243 @@ +// this is a parity xitca-web implementation of "pure" io_uring runtime comparing performance with +// tokio_uring's epoll + io_uring runtime. + +#![feature(async_iterator)] + +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +mod db; +mod db_pool; +mod ser; +mod util; + +use std::{cell::RefCell, io, net::SocketAddr, rc::Rc, time::Duration}; + +use compio::net::TcpOpts; +use xitca_http::{ + body::Once, + bytes::Bytes, + date::{DateTime, DateTimeState}, + h1::{RequestBody, dispatcher_compio::Dispatcher}, + http::{ + self, HeaderValue, IntoResponse as _, RequestExt, StatusCode, + const_header_value::{JSON, TEXT_HTML_UTF8, TEXT_UTF8}, + header::{CONTENT_TYPE, SERVER}, + }, + util::{ + middleware::context::{Context, ContextBuilder}, + service::{ + route::get, + router::{Router, RouterError}, + }, + }, +}; +use xitca_service::{Service, ServiceExt, fn_service}; + +use self::{ + ser::{HELLO, Message}, + util::{HandleResult, QueryParse}, +}; + +type Request = http::Request>; + +type Response = http::Response>; + +type Ctx<'a> = Context<'a, Request, db_pool::Client>; + +fn main() -> io::Result<()> { + let cores = std::thread::available_parallelism().map(|num| num.get()).unwrap_or(56); + + let mut ids = core_affinity::get_core_ids().unwrap(); + + let addr = "0.0.0.0:8080".parse::().unwrap(); + + let worker = move |id: Option| { + if let Some(id) = id { + let _ = core_affinity::set_for_current(id); + } + + compio::runtime::RuntimeBuilder::new().build().unwrap().block_on(async { + let listener = + compio::net::TcpListener::bind_with_options(addr, TcpOpts::new().reuse_address(true).reuse_port(true)) + .await?; + + let service = Router::new() + .insert( + "/plaintext", + get(fn_service(async |ctx: Ctx| { + let (req, _) = ctx.into_parts(); + let mut res = req.into_response(const { Bytes::from_static(HELLO.as_bytes()) }); + res.headers_mut().insert(CONTENT_TYPE, TEXT_UTF8); + Ok(res) + })), + ) + .insert( + "/json", + get(fn_service(async |ctx: Ctx| { + let (req, _) = ctx.into_parts(); + json_response(req, Message::HELLO) + })), + ) + .insert( + "/db", + get(fn_service(async |ctx: Ctx| { + let (req, cli) = ctx.into_parts(); + cli.db().await.and_then(|w| json_response(req, &w)) + })), + ) + .insert( + "/fortunes", + get(fn_service(async |ctx: Ctx| { + let (req, cli) = ctx.into_parts(); + let fortunes = cli.fortunes().await?.render_once()?; + let mut res = req.into_response(Bytes::from(fortunes)); + res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8); + Ok(res) + })), + ) + .insert( + "/queries", + get(fn_service(async |ctx: Ctx| { + let (req, cli) = ctx.into_parts(); + let num = req.uri().query().parse_query(); + cli.queries(num).await.and_then(|w| json_response(req, &w)) + })), + ) + .insert( + "/updates", + get(fn_service(async |ctx: Ctx| { + let (req, cli) = ctx.into_parts(); + let num = req.uri().query().parse_query(); + cli.updates(num).await.and_then(|w| json_response(req, &w)) + })), + ) + .enclosed(ContextBuilder::new(db_pool::Client::create)) + .enclosed_fn(async |service, req| { + let mut res = service.call(req).await.unwrap_or_else(error_handler); + res.headers_mut().insert(SERVER, HeaderValue::from_static("x")); + Ok::<_, core::convert::Infallible>(res) + }); + + let router = service.call(()).await.unwrap(); + + let service = Rc::new((router, Time::new())); + + loop { + match listener.accept().await { + Ok((stream, addr)) => { + let service = service.clone(); + compio::runtime::spawn(async move { + let _ = Dispatcher::<_, _, _, 64, { usize::MAX }, { usize::MAX }>::run( + stream, addr, &service.0, &service.1, + ) + .await; + }) + .detach(); + } + Err(e) => return Err(e), + }; + } + }) + }; + + let handle = core::iter::repeat_with(|| { + let id = ids.pop(); + std::thread::spawn(move || worker(id)) + }) + .take(cores - 1) + .collect::>(); + + // unrealistic due to no signal handling, not shutdown handling. when killing this process all resources that + // need clean async shutdown will be leaked. + worker(ids.pop())?; + for handle in handle { + let _ = handle.join().unwrap(); + } + + Ok(()) +} + +#[cold] +#[inline(never)] +fn error_handler(e: RouterError) -> Response { + let status = match e { + RouterError::Match(_) => StatusCode::NOT_FOUND, + RouterError::NotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED, + RouterError::Service(e) => { + eprintln!("Internal Error: {e}"); + StatusCode::INTERNAL_SERVER_ERROR + } + }; + http::Response::builder() + .status(status) + .body(Once::new(Bytes::new())) + .unwrap() +} + +fn json_response(req: Request, val: &impl serde_core::Serialize) -> HandleResult { + let buf = ser::json_serialize(val)?; + let mut res = req.into_response(Bytes::from(buf)); + res.headers_mut().insert(CONTENT_TYPE, JSON); + Ok(res) +} + +struct Time(Rc>); + +impl Time { + fn new() -> Self { + let state = Rc::new(RefCell::new(DateTimeState::default())); + let state2 = state.clone(); + compio::runtime::spawn(async move { + let mut interval = compio::runtime::time::interval(Duration::from_secs(1)); + loop { + let _ = interval.tick().await; + *state2.borrow_mut() = DateTimeState::default(); + } + }) + .detach(); + Self(state) + } +} + +impl DateTime for Time { + fn with_date(&self, f: F) -> O + where + F: FnOnce(&[u8]) -> O, + { + let date = self.0.borrow(); + f(&date.date[..]) + } + + fn now(&self) -> tokio::time::Instant { + self.0.borrow().now + } +} + +struct CompIoConnector; + +impl xitca_postgres::pool::Connect for CompIoConnector { + async fn connect(&self, cfg: xitca_postgres::Config) -> Result { + let (cli, drv) = compio::runtime::spawn_blocking(|| { + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(xitca_postgres::Postgres::new(cfg).connect()) + }) + .await + .unwrap()?; + + let drv = drv.try_into_tcp().expect("raw tcp is used for database connection"); + let drv = xitca_postgres::CompIoDriver::from_tcp(drv)?; + + compio::runtime::spawn(async move { + use core::{async_iter::AsyncIterator, future::poll_fn, pin::pin}; + + let mut drv = pin!(drv.into_async_iter()); + while poll_fn(|cx| drv.as_mut().poll_next(cx)).await.is_some() {} + }) + .detach(); + Ok(cli) + } +} diff --git a/frameworks/Rust/xitca-web/src/main_orm.rs b/frameworks/Rust/xitca-web/src/main_orm.rs index 6fd0e7a3732..083a85b3c97 100755 --- a/frameworks/Rust/xitca-web/src/main_orm.rs +++ b/frameworks/Rust/xitca-web/src/main_orm.rs @@ -12,25 +12,29 @@ mod orm; #[path = "./db_toasty.rs"] mod orm; -use ser::{Num, World}; -use util::{HandleResult, SERVER_HEADER_VALUE}; use xitca_web::{ App, codegen::route, handler::{html::Html, json::Json, query::Query, state::StateRef}, - http::{WebResponse, header::SERVER}, + http::{HeaderValue, WebResponse, header::SERVER}, }; use orm::Pool; +use ser::{Message, Num, World}; +use util::HandleResult; fn main() -> std::io::Result<()> { App::new() .with_async_state(Pool::create) + .at("/json", Json(Message::HELLO)) .at_typed(db) .at_typed(fortunes) .at_typed(queries) .at_typed(updates) - .map(header) + .map(|mut res: WebResponse| { + res.headers_mut().insert(SERVER, HeaderValue::from_static("xitca-web")); + res + }) .serve() .disable_vectored_write() .bind("0.0.0.0:8080")? @@ -38,28 +42,22 @@ fn main() -> std::io::Result<()> { .wait() } -fn header(mut res: WebResponse) -> WebResponse { - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - res -} - #[route("/db", method = get)] async fn db(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { - pool.get_world().await.map(Json) + pool.db().await.map(Json) } #[route("/fortunes", method = get)] async fn fortunes(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { - let html = pool.tell_fortune().await?.render_once()?; - Ok(Html(html)) + pool.fortunes().await?.render_once().map(Html) } #[route("/queries", method = get)] async fn queries(Query(Num(num)): Query, StateRef(pool): StateRef<'_, Pool>) -> HandleResult>> { - pool.get_worlds(num).await.map(Json) + pool.queries(num).await.map(Json) } #[route("/updates", method = get)] async fn updates(Query(Num(num)): Query, StateRef(pool): StateRef<'_, Pool>) -> HandleResult>> { - pool.update(num).await.map(Json) + pool.updates(num).await.map(Json) } diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index 1597e19ab09..adc3240f747 100755 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -1,46 +1,22 @@ -#![allow(dead_code)] +//! light weight proc macro are manually expanded to reduce compile time resource usage +//! there is no runtime perf difference between manual expansion and deault code generation -use std::borrow::Cow; +use serde_core::{Serialize, Serializer, ser::SerializeStruct}; -use serde_core::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct}; -use xitca_http::{ - body::Once, - bytes::Bytes, - http::{ - self, IntoResponse as _, RequestExt, StatusCode, - const_header_value::{TEXT_HTML_UTF8, TEXT_UTF8}, - header::CONTENT_TYPE, - }, -}; +#[cfg(feature = "pg")] +use xitca_unsafe_collection::bytes::BytesStr; -use crate::util::Error; - -const HELLO: &str = "Hello, World!"; -const HELLO_BYTES: &[u8] = HELLO.as_bytes(); - -#[derive(Clone)] -pub struct Message { - message: &'static str, -} - -impl Message { - #[inline] - pub const fn new() -> Self { - Self { message: HELLO } - } -} - -pub struct Num(pub u16); +use crate::util::HandleResult; #[cfg_attr(feature = "diesel", derive(diesel::Queryable))] -#[cfg_attr(feature = "toasty", derive(toasty::Model))] -#[cfg_attr(feature = "toasty", table = "world")] +#[cfg_attr(feature = "toasty", derive(toasty::Model), table = "world")] pub struct World { #[cfg_attr(feature = "toasty", key)] pub id: i32, pub randomnumber: i32, } +#[cfg(not(feature = "diesel"))] impl World { #[inline] pub const fn new(id: i32, randomnumber: i32) -> Self { @@ -48,22 +24,49 @@ impl World { } } +impl Serialize for World { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut res = serializer.serialize_struct("World", 2)?; + res.serialize_field("id", &self.id)?; + res.serialize_field("randomnumber", &self.randomnumber)?; + res.end() + } +} + #[cfg_attr(feature = "diesel", derive(diesel::Queryable))] -#[cfg_attr(feature = "toasty", derive(toasty::Model))] -#[cfg_attr(feature = "toasty", table = "fortune")] +#[cfg_attr(feature = "toasty", derive(toasty::Model), table = "fortune")] pub struct Fortune { #[cfg_attr(feature = "toasty", key)] pub id: i32, - pub message: Cow<'static, str>, + pub message: FortuneMessage, } +#[cfg(feature = "zero-copy")] +type FortuneMessage = BytesStr; + +#[cfg(not(feature = "zero-copy"))] +type FortuneMessage = String; + impl Fortune { + const RUNTIME: &str = "Additional fortune added at request time."; + + #[cfg(feature = "zero-copy")] + fn runtime() -> Self { + Self::new(0, const { BytesStr::from_static(Self::RUNTIME) }) + } + + #[cfg(not(feature = "zero-copy"))] #[inline] - pub fn new(id: i32, message: impl Into>) -> Self { - Self { - id, - message: message.into(), - } + fn runtime() -> Self { + Self::new(0, String::from(Self::RUNTIME)) + } + + #[inline] + pub const fn new(id: i32, message: FortuneMessage) -> Self { + Self { id, message } } } @@ -71,12 +74,16 @@ pub struct Fortunes { items: Vec, } -// this is roughly the code generated by sailfish::TemplateOnce macro. -// using the macro does not have any perf cost and this piece of code is expanded manually to speed up compile time of -// bench to reduce resource usage of bench runner -#[cfg(feature = "template")] impl Fortunes { - pub fn render_once(self) -> sailfish::RenderResult { + #[inline] + pub fn new(mut items: Vec) -> Self { + items.push(Fortune::runtime()); + items.sort_by(|a, b| a.message.cmp(&b.message)); + Self { items } + } + + #[cfg(feature = "template")] + pub fn render_once(self) -> HandleResult { use sailfish::runtime::{Buffer, Render}; const PREFIX: &str = "\n\nFortunes\n\n
idmessage
{}{}
\n\n"; @@ -89,7 +96,7 @@ impl Fortunes { buf.push_str(""); } buf.push_str(SUFFIX); @@ -98,77 +105,15 @@ impl Fortunes { } } -impl Fortunes { - #[inline] - pub fn new(mut items: Vec) -> Self { - items.push(Fortune::new(0, "Additional fortune added at request time.")); - items.sort_by(|a, b| a.message.cmp(&b.message)); - Self { items } - } -} - -impl<'de> Deserialize<'de> for Num { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use core::fmt; - - use serde_core::de::{Error, MapAccess, Visitor}; - - const FIELDS: &[&str] = &["q"]; - - struct Field; - - impl<'de> Deserialize<'de> for Field { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct FieldVisitor; - - impl Visitor<'_> for FieldVisitor { - type Value = Field; +pub const HELLO: &str = "Hello, World!"; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("`q`") - } - - fn visit_str(self, value: &str) -> Result - where - E: Error, - { - match value { - "q" => Ok(Field), - _ => Err(Error::unknown_field(value, FIELDS)), - } - } - } - - deserializer.deserialize_identifier(FieldVisitor) - } - } - - struct NumVisitor; - - impl<'de> Visitor<'de> for NumVisitor { - type Value = Num; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct Num") - } - - fn visit_map(self, mut map: V) -> Result - where - V: MapAccess<'de>, - { - map.next_key::()?.ok_or_else(|| Error::missing_field("q"))?; - Ok(Num(map.next_value().unwrap_or(1).clamp(1, 500))) - } - } +#[derive(Clone)] +pub struct Message { + message: &'static str, +} - deserializer.deserialize_struct("Num", FIELDS, NumVisitor) - } +impl Message { + pub const HELLO: &Self = &Self { message: HELLO }; } impl Serialize for Message { @@ -182,62 +127,82 @@ impl Serialize for Message { } } -impl Serialize for World { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut res = serializer.serialize_struct("World", 2)?; - res.serialize_field("id", &self.id)?; - res.serialize_field("randomnumber", &self.randomnumber)?; - res.end() - } -} +#[cfg(feature = "web-codegen")] +pub use num::Num; -pub type Request = http::Request>; -pub type Response = http::Response>; +#[cfg(feature = "web-codegen")] +mod num { + use serde_core::{Deserialize, Deserializer}; -pub trait IntoResponse: Sized { - #[cfg(any(feature = "json", feature = "perf-json"))] - fn json_response(self, state: &crate::util::State, val: &impl Serialize) -> Result; + pub struct Num(pub u16); - fn text_response(self) -> Result; + impl<'de> Deserialize<'de> for Num { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use core::fmt; - fn html_response(self, val: String) -> Result; -} + use serde_core::de::{Error, MapAccess, Visitor}; -impl IntoResponse for Request { - #[cfg(any(feature = "json", feature = "perf-json"))] - fn json_response(self, state: &crate::util::State, val: &impl Serialize) -> Result { - let buf = &mut *state.write_buf.borrow_mut(); - #[cfg(all(feature = "json", not(feature = "perf-json")))] - serde_json::to_writer(xitca_http::bytes::BufMutWriter(buf), val)?; + const FIELDS: &[&str] = &["q"]; - #[cfg(all(feature = "perf-json", not(feature = "json")))] - sonic_rs::to_writer(xitca_http::bytes::BufMut::writer(&mut *buf), val)?; + struct Field; - let mut res = self.into_response(buf.split().freeze()); - res.headers_mut() - .insert(CONTENT_TYPE, xitca_http::http::const_header_value::JSON); - Ok(res) - } + impl<'de> Deserialize<'de> for Field { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FieldVisitor; - fn text_response(self) -> Result { - let mut res = self.into_response(const { Bytes::from_static(HELLO_BYTES) }); - res.headers_mut().insert(CONTENT_TYPE, TEXT_UTF8); - Ok(res) - } + impl Visitor<'_> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`q`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "q" => Ok(Field), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + } - fn html_response(self, val: String) -> Result { - let mut res = self.into_response(Bytes::from(val)); - res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8); - Ok(res) + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct NumVisitor; + + impl<'de> Visitor<'de> for NumVisitor { + type Value = Num; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Num") + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + map.next_key::()?.ok_or_else(|| Error::missing_field("q"))?; + Ok(Num(map.next_value().unwrap_or(1).clamp(1, 500))) + } + } + + deserializer.deserialize_struct("Num", FIELDS, NumVisitor) + } } } -pub fn error_response(status: StatusCode) -> Response { - http::Response::builder() - .status(status) - .body(Once::new(Bytes::new())) - .unwrap() -} +#[cfg(all(feature = "perf-json", not(feature = "json")))] +pub use sonic_rs::to_vec as json_serialize; + +#[cfg(all(feature = "json", not(feature = "perf-json")))] +pub use serde_json::to_vec as json_serialize; diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index bccb7549ac6..2a7576efbed 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -1,54 +1,44 @@ -#![allow(dead_code)] - -use rand::{Rng, SeedableRng, distr::Uniform, rngs::SmallRng}; -use xitca_http::{bytes::BytesMut, http::header::HeaderValue}; - -pub trait QueryParse { - fn parse_query(self) -> u16; -} +use rand::{ + RngExt, SeedableRng, + distr::Uniform, + rngs::{SmallRng, SysRng}, +}; + +#[cfg(feature = "pg")] +pub use parse::QueryParse; + +#[cfg(feature = "pg")] +mod parse { + pub trait QueryParse { + fn parse_query(self) -> u16; + } -impl QueryParse for Option<&str> { - fn parse_query(self) -> u16 { - self.and_then(|q| q.find('q').map(|pos| q.split_at(pos + 2).1.parse_query())) - .unwrap_or(1) + impl QueryParse for Option<&str> { + fn parse_query(self) -> u16 { + self.and_then(|q| q.find('q').map(|pos| q.split_at(pos + 2).1.parse_query())) + .unwrap_or(1) + } } -} -impl QueryParse for &str { - fn parse_query(self) -> u16 { - use atoi::FromRadix10; - u16::from_radix_10(self.as_bytes()).0.clamp(1, 500) + impl QueryParse for &str { + fn parse_query(self) -> u16 { + use atoi::FromRadix10; + u16::from_radix_10(self.as_bytes()).0.clamp(1, 500) + } } } -#[allow(clippy::declare_interior_mutable_const)] -pub const SERVER_HEADER_VALUE: HeaderValue = HeaderValue::from_static("X"); - pub type Error = Box; pub type HandleResult = Result; pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; -pub struct State { - pub client: DB, - pub write_buf: core::cell::RefCell, -} - -impl State { - pub fn new(client: DB) -> Self { - Self { - client, - write_buf: Default::default(), - } - } -} - pub struct Rand(SmallRng); impl Default for Rand { fn default() -> Self { - Self(SmallRng::from_os_rng()) + Self(SmallRng::try_from_rng(&mut SysRng).unwrap()) } } diff --git a/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile b/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile index 4a5bbf9d898..af5cf8c8474 100644 --- a/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-barebone.dockerfile @@ -1,9 +1,9 @@ -FROM rust:1.91.1 +FROM rust:1.93 ADD ./ /xitca-web WORKDIR /xitca-web -RUN cargo build --release --bin xitca-web-barebone --features perf,perf-json,pg,template +RUN cargo build --release --bin xitca-web-barebone --features perf,perf-json,pg,template,zero-copy EXPOSE 8080 diff --git a/frameworks/Rust/xitca-web/xitca-web-compio.dockerfile b/frameworks/Rust/xitca-web/xitca-web-compio.dockerfile new file mode 100644 index 00000000000..a9e25de9cad --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-compio.dockerfile @@ -0,0 +1,11 @@ +FROM rust:1.93 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN rustup default nightly-2026-02-24 +RUN cargo build --release --bin xitca-web-compio --features compio,perf,perf-json,pg,router,template,zero-copy + +EXPOSE 8080 + +CMD ./target/release/xitca-web-compio diff --git a/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile b/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile old mode 100755 new mode 100644 index 66ff80b5dfd..7236414aebf --- a/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.91.1 +FROM rust:1.93 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile b/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile old mode 100755 new mode 100644 index 30a2cea648d..0cce5dac782 --- a/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web-toasty.dockerfile @@ -1,8 +1,10 @@ -FROM rust:1.91.1 +FROM rust:1.93 ADD ./ /xitca-web WORKDIR /xitca-web +# nightly rust enables toasty to use more static dispatch of async trait +RUN rustup default nightly-2026-02-24 RUN cargo build --release --bin xitca-web-toasty --features perf,template,toasty,web-codegen EXPOSE 8080 diff --git a/frameworks/Rust/xitca-web/xitca-web.dockerfile b/frameworks/Rust/xitca-web/xitca-web.dockerfile index 86d7818009e..e20022de7d2 100644 --- a/frameworks/Rust/xitca-web/xitca-web.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web.dockerfile @@ -1,9 +1,13 @@ -FROM rust:1.91.1 +FROM rust:1.93 ADD ./ /xitca-web WORKDIR /xitca-web -RUN cargo build --release --bin xitca-web --features io-uring,json,pg,router,template +# for official run +# RUN cargo build --release --bin xitca-web --features io-uring,pg,router,template,zero-copy,json + +# for continuous run +RUN cargo build --release --bin xitca-web --features io-uring,pg,router,template,zero-copy,perf-json,perf-allocator EXPOSE 8080 diff --git a/frameworks/Scala/http4s/http4s.dockerfile b/frameworks/Scala/http4s/http4s.dockerfile index e059893aa79..75c1b5c322d 100644 --- a/frameworks/Scala/http4s/http4s.dockerfile +++ b/frameworks/Scala/http4s/http4s.dockerfile @@ -11,7 +11,7 @@ RUN sbt assembly -batch && \ rm -Rf ~/.ivy2 && \ rm -Rf /var/cache -FROM openjdk:21 +FROM eclipse-temurin:21-jre-jammy WORKDIR /http4s COPY --from=builder /http4s/http4s-assembly-1.0.jar /http4s/http4s-assembly-1.0.jar diff --git a/frameworks/Scala/scalene/benchmark_config.json b/frameworks/Scala/scalene/benchmark_config.json index e208ae8d5ba..a0d2f166148 100644 --- a/frameworks/Scala/scalene/benchmark_config.json +++ b/frameworks/Scala/scalene/benchmark_config.json @@ -18,7 +18,8 @@ "webserver": "None", "os": "Linux", "display_name": "scalene", - "notes": "" + "notes": "", + "tags": ["broken"] } }] } diff --git a/frameworks/Scala/vertx-web-scala/.scalafmt.conf b/frameworks/Scala/vertx-web-scala/.scalafmt.conf index 0f9a7c14c34..de4ccefc844 100644 --- a/frameworks/Scala/vertx-web-scala/.scalafmt.conf +++ b/frameworks/Scala/vertx-web-scala/.scalafmt.conf @@ -1,2 +1,2 @@ -version=2.0.0-RC8 +version=3.10.2 maxColumn = 120 diff --git a/frameworks/Scala/vertx-web-scala/README.md b/frameworks/Scala/vertx-web-scala/README.md index 7b5f51b8f0e..e6d1e2e47ee 100755 --- a/frameworks/Scala/vertx-web-scala/README.md +++ b/frameworks/Scala/vertx-web-scala/README.md @@ -13,8 +13,8 @@ This is the Vert.x Web Scala portion of a [benchmarking test suite](../) compari ## Versions -* [Java OpenJDK 17](https://openjdk.java.net/) -* [Vert.x 3.9](https://vertx.io/) +* [Java OpenJDK 25](https://openjdk.java.net/) +* [Vert.x 5.0.5](https://vertx.io/) ## Test URLs diff --git a/frameworks/Scala/vertx-web-scala/build.sbt b/frameworks/Scala/vertx-web-scala/build.sbt index 5a75b7a6502..8c683daa87b 100644 --- a/frameworks/Scala/vertx-web-scala/build.sbt +++ b/frameworks/Scala/vertx-web-scala/build.sbt @@ -2,22 +2,23 @@ name := "vertx-web-scala" version := "1" -scalaVersion := "2.12.20" +scalaVersion := "3.7.4" lazy val root = (project in file(".")).enablePlugins(SbtTwirl) -val vertxScalaVersion = "3.9.1" -val vertxVersion = "3.9.15" -val nettyVersion = "4.1.89.Final" +val vertxScalaVersion = "5.0.0.CR2" +val vertxVersion = "5.0.5" +val nettyVersion = "4.2.7.Final" // the version that Vert.x depends on libraryDependencies += "io.vertx" %% "vertx-lang-scala" % vertxScalaVersion -libraryDependencies += "io.vertx" %% "vertx-web-scala" % vertxScalaVersion +libraryDependencies += "io.vertx" % "vertx-web" % vertxVersion libraryDependencies += "io.vertx" % "vertx-codegen" % vertxVersion libraryDependencies += "io.vertx" % "vertx-pg-client" % vertxVersion libraryDependencies += "io.netty" % "netty-transport-native-kqueue" % nettyVersion classifier "osx-x86_64" -libraryDependencies += "io.netty" % "netty-transport-native-epoll" % nettyVersion classifier "linux-x86_64" -libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.4.5" -libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5" +//libraryDependencies += "io.netty" % "netty-transport-native-epoll" % nettyVersion classifier "linux-x86_64" +libraryDependencies += "io.netty" % "netty-transport-native-io_uring" % nettyVersion classifier "linux-x86_64" +libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.5.22" +libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.6" Compile / mainClass := Some("vertx.App") diff --git a/frameworks/Scala/vertx-web-scala/project/build.properties b/frameworks/Scala/vertx-web-scala/project/build.properties index cc68b53f1a3..01a16ed1465 100644 --- a/frameworks/Scala/vertx-web-scala/project/build.properties +++ b/frameworks/Scala/vertx-web-scala/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.11 +sbt.version=1.11.7 diff --git a/frameworks/Scala/vertx-web-scala/project/plugins.sbt b/frameworks/Scala/vertx-web-scala/project/plugins.sbt index 60d9c35aa7f..40a6638a0de 100644 --- a/frameworks/Scala/vertx-web-scala/project/plugins.sbt +++ b/frameworks/Scala/vertx-web-scala/project/plugins.sbt @@ -1,3 +1,3 @@ -addSbtPlugin("com.typesafe.play" % "sbt-twirl" % "1.5.2") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.1") +addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.9") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.6") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") diff --git a/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala b/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala index 0f2991c3b47..59a99b8bf67 100644 --- a/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala +++ b/frameworks/Scala/vertx-web-scala/src/main/scala/vertx/App.scala @@ -1,32 +1,32 @@ package vertx -import java.io.{ByteArrayOutputStream, File, IOException} -import java.nio.file.Files -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.util.concurrent.ThreadLocalRandom - import com.typesafe.scalalogging.Logger import io.vertx.core.buffer.Buffer -import io.vertx.core.http.HttpHeaders +import io.vertx.core.http.{HttpHeaders, HttpServerRequest, HttpServerResponse} import io.vertx.core.json.{JsonArray, JsonObject} -import io.vertx.core.{AsyncResult, Handler, VertxOptions => JVertxOptions} -import io.vertx.lang.scala.{ScalaVerticle, VertxExecutionContext} -import io.vertx.pgclient._ -import io.vertx.scala.core.http.{HttpServer, HttpServerRequest, HttpServerResponse} -import io.vertx.scala.core.{VertxOptions, _} -import io.vertx.scala.ext.web.Router -import io.vertx.sqlclient._ +import io.vertx.core.{Handler, Vertx, VertxOptions as JVertxOptions} +import io.vertx.ext.web.Router +import io.vertx.lang.scala.{ScalaVerticle, VertxExecutionContext, asScala} +import io.vertx.pgclient.* +import io.vertx.scala.core.* +import io.vertx.sqlclient.* import vertx.model.{Fortune, Message, World} -import scala.collection.JavaConverters._ -import scala.concurrent.{Future, Promise} -import scala.util.{Failure, Sorting, Success, Try} +import java.io.{ByteArrayOutputStream, File, IOException} +import java.nio.file.Files +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.util.concurrent.ThreadLocalRandom +import scala.compiletime.uninitialized +import scala.jdk.CollectionConverters.* +import scala.util.{Sorting, Try, boundary} case class Header(name: CharSequence, value: String) class App extends ScalaVerticle { - import App._ + + import App.* + private val HELLO_WORLD = "Hello, world!" private val HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD, "UTF-8") private val SERVER = "vert.x" @@ -37,14 +37,14 @@ class App extends ScalaVerticle { private var dateString: String = "" - private var server: HttpServer = _ - private var client: PgConnection = _ + private var server: io.vertx.core.http.HttpServer = uninitialized + private var client: PgConnection = uninitialized private def refreshDateHeader(): Unit = dateString = App.createDateHeader() - override def startFuture(): Future[_] = { + override def start(promise: scala.concurrent.Promise[Unit]): Unit = { refreshDateHeader() - vertx.setPeriodic(1000, (_: Long) => refreshDateHeader()) + vertx.setPeriodic(1000, _ => refreshDateHeader()) val pgConnectOptions = new PgConnectOptions() .setDatabase(config.getString("database")) @@ -55,15 +55,11 @@ class App extends ScalaVerticle { .setCachePreparedStatements(true) .setPipeliningLimit(100000) - val jVertx = vertx.asJava.asInstanceOf[io.vertx.core.Vertx] - val pgConnectionPromise = Promise[Unit] - PgConnection.connect( - jVertx, - pgConnectOptions, - (ar => { - client = ar.result() - pgConnectionPromise.success() - }): Handler[AsyncResult[PgConnection]] + val pgConnectionFuture = PgConnection.connect( + vertx, + pgConnectOptions + ).onSuccess(r => + client = r ) val router = Router.router(vertx) @@ -76,12 +72,11 @@ class App extends ScalaVerticle { val port = 8080 server = vertx.createHttpServer() - val httpServerPromise = Promise[Unit] - server - .requestHandler(router.accept) - .listen(port, (_ => httpServerPromise.success()): Handler[AsyncResult[HttpServer]]) + val httpServerFuture = server + .requestHandler(router) + .listen(port) - pgConnectionPromise.future.flatMap(_ => httpServerPromise.future) + promise.completeWith(pgConnectionFuture.flatMap(_ => httpServerFuture.map(())).asScala) } override def stop(): Unit = Option(server).foreach(_.close()) @@ -102,10 +97,11 @@ class App extends ScalaVerticle { private def handleDb(request: HttpServerRequest): Unit = client - .preparedQuery("SELECT id, randomnumber from WORLD where id=$1") + .preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") .execute( - Tuple.of(App.randomWorld(), Nil: _*), - (ar: AsyncResult[RowSet[Row]]) => { + Tuple.of(App.randomWorld())) + .andThen( + ar => { if (ar.succeeded) { val resultSet = ar.result.iterator if (!resultSet.hasNext) { @@ -128,15 +124,15 @@ class App extends ScalaVerticle { var failed = false while (i < queries) { client - .preparedQuery("SELECT id, randomnumber from WORLD where id=$1") - .execute( - Tuple.of(App.randomWorld(), Nil: _*), - (ar: AsyncResult[RowSet[Row]]) => { + .preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") + .execute(Tuple.of(App.randomWorld())) + .andThen( + ar => boundary { if (!failed) { if (ar.failed) { failed = true sendError(request, ar.cause, "Failed to handle Queries request") - return + boundary.break() } // we need a final reference val row = ar.result.iterator.next @@ -159,13 +155,13 @@ class App extends ScalaVerticle { val batch = worlds.map(world => Tuple.of(world.randomNumber, world.id)).toList.asJava conn - .preparedQuery("UPDATE world SET randomnumber=$1 WHERE id=$2") - .executeBatch( - batch, - (ar: AsyncResult[RowSet[Row]]) => { + .preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") + .executeBatch(batch) + .andThen( + ar => boundary { if (ar.failed) { sendError(request, ar.cause, "handleUpdates: failed to update DB") - return + boundary.break() } responseWithHeaders(request.response, contentTypeJson) @@ -184,15 +180,14 @@ class App extends ScalaVerticle { val id = App.randomWorld() val index = i client - .preparedQuery("SELECT id, randomnumber from WORLD where id=$1") - .execute( - Tuple.of(id, Nil: _*), - (ar2: AsyncResult[RowSet[Row]]) => { + .preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") + .execute(Tuple.of(id)).andThen( + ar2 => boundary { if (!failed) { if (ar2.failed) { failed = true sendError(request, ar2.cause, "handleUpdates: failed to read DB") - return + boundary.break() } worlds(index) = World(ar2.result.iterator.next.getInteger(0), App.randomWorld()) queryCount += 1 @@ -206,15 +201,16 @@ class App extends ScalaVerticle { private def handleFortunes(request: HttpServerRequest): Unit = client - .preparedQuery("SELECT id, message from FORTUNE") - .execute( - (ar: AsyncResult[RowSet[Row]]) => { + .preparedQuery("SELECT id, message FROM fortune") + .execute() + .andThen( + ar => boundary { val response = request.response if (ar.succeeded) { val resultSet = ar.result.iterator if (!resultSet.hasNext) { response.setStatusCode(404).end("No results") - return + boundary.break() } val fortunes = (resultSet.asScala .map(row => Fortune(row.getInteger(0), row.getString(1))) ++ @@ -233,25 +229,26 @@ class App extends ScalaVerticle { object App { val logger: Logger = Logger[App] val defaultConfigPath = "src/main/conf/config.json" + def main(args: Array[String]): Unit = { - val config = new JsonObject(Files.readString(new File(if(args.length < 1) defaultConfigPath else args(0)).toPath)) + val config = new JsonObject(Files.readString(new File(if (args.length < 1) defaultConfigPath else args(0)).toPath)) val vertx = Vertx.vertx(VertxOptions().setPreferNativeTransport(true)) printConfig(vertx) vertx.exceptionHandler(_.printStackTrace()) - implicit val executionContext: VertxExecutionContext = VertxExecutionContext(vertx.getOrCreateContext()) + implicit val executionContext: VertxExecutionContext = VertxExecutionContext(vertx, vertx.getOrCreateContext()) vertx - .deployVerticleFuture( - ScalaVerticle.nameForVerticle[App], + .deployVerticle( + ScalaVerticle.nameForVerticle[App](), DeploymentOptions().setInstances(JVertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE).setConfig(config) ) - .onComplete { - case _: Success[String] => logger.info("Server listening on port 8080") - case f: Failure[String] => logger.error("Unable to start application", f.exception) - } + .onComplete(ar => + if (ar.succeeded()) logger.info("Server listening on port 8080") + else logger.error("Unable to start application", ar.cause) + ) } def createDateHeader(): String = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now) @@ -259,8 +256,7 @@ object App { def randomWorld(): Int = 1 + ThreadLocalRandom.current.nextInt(10000) def getQueries(request: HttpServerRequest): Int = - request - .getParam("queries") + Option(request.getParam("queries")) .flatMap(param => Try(param.toInt).toOption) .map(number => Math.min(500, Math.max(1, number))) .getOrElse(1) diff --git a/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile b/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile index 047d042d2dc..cecd42be414 100644 --- a/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile +++ b/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile @@ -1,6 +1,6 @@ -FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.12.20 +FROM sbtscala/scala-sbt:eclipse-temurin-25.0.1_8_1.11.7_3.7.4 -ARG SBT_VERSION=1.8.2 +ARG SBT_VERSION=1.11.7 WORKDIR /vertx COPY src src @@ -25,5 +25,5 @@ CMD export DBIP=`getent hosts tfb-database | awk '{ print $1 }'` && \ -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ -jar \ - target/scala-2.12/vertx-web-scala-assembly-1.jar \ + target/scala-3.7.4/vertx-web-scala-assembly-1.jar \ src/main/conf/config.json diff --git a/frameworks/Swift/swift-nio/app/Package.swift b/frameworks/Swift/swift-nio/app/Package.swift index e15bcceb4a6..648caa517ea 100644 --- a/frameworks/Swift/swift-nio/app/Package.swift +++ b/frameworks/Swift/swift-nio/app/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.1 +// swift-tools-version:5.10 import PackageDescription let package = Package( @@ -6,16 +6,14 @@ let package = Package( platforms: [ .macOS(.v10_15) ], - products: [ - .executable(name: "app", targets: ["App"]) - ], dependencies: [ - .package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"), + .package(url: "https://github.com/apple/swift-nio.git", from: "2.90.0"), ], targets: [ - .target(name: "App", dependencies: [ - "NIO", - "NIOHTTP1", + .executableTarget(name: "App", dependencies: [ + .product(name: "NIOCore", package: "swift-nio"), + .product(name: "NIOHTTP1", package: "swift-nio"), + .product(name: "NIOPosix", package: "swift-nio") ], path: "Sources") ] ) diff --git a/frameworks/Swift/swift-nio/app/Sources/main.swift b/frameworks/Swift/swift-nio/app/Sources/main.swift index ce51a8a7b0c..b42f27d77f8 100644 --- a/frameworks/Swift/swift-nio/app/Sources/main.swift +++ b/frameworks/Swift/swift-nio/app/Sources/main.swift @@ -1,23 +1,12 @@ import Foundation -import NIO +import NIOCore import NIOHTTP1 +import NIOPosix struct JSONTestResponse: Encodable { let message = "Hello, World!" } -enum Constants { - static let httpVersion = HTTPVersion(major: 1, minor: 1) - static let serverName = "SwiftNIO" - - static let plainTextResponse: StaticString = "Hello, World!" - static let plainTextResponseLength = plainTextResponse.utf8CodeUnitCount - static let plainTextResponseLengthString = String(plainTextResponseLength) - - static let jsonResponseLength = try! JSONEncoder().encode(JSONTestResponse()).count - static let jsonResponseLengthString = String(jsonResponseLength) -} - private final class HTTPHandler: ChannelInboundHandler { public typealias InboundIn = HTTPServerRequestPart public typealias OutboundOut = HTTPServerResponsePart @@ -25,16 +14,12 @@ private final class HTTPHandler: ChannelInboundHandler { let jsonEncoder: JSONEncoder let dateCache: RFC1123DateCache - var plaintextBuffer: ByteBuffer - var jsonBuffer: ByteBuffer + var outputBuffer: ByteBuffer init(channel: Channel) { - let allocator = ByteBufferAllocator() - self.plaintextBuffer = allocator.buffer(capacity: Constants.plainTextResponseLength) - self.plaintextBuffer.writeStaticString(Constants.plainTextResponse) - self.jsonBuffer = allocator.buffer(capacity: Constants.jsonResponseLength) - self.jsonEncoder = .init() + self.outputBuffer = .init() self.dateCache = .on(channel.eventLoop) + self.jsonEncoder = JSONEncoder() } func channelRead(context: ChannelHandlerContext, data: NIOAny) { @@ -42,50 +27,47 @@ private final class HTTPHandler: ChannelInboundHandler { case .head(let request): switch request.uri { case "/plaintext": - self.processPlaintext(context: context) + self.outputBuffer.clear() + self.outputBuffer.writeStaticString("Hello, World!") + let responseHead = self.responseHead( + contentType: "text/plain", + contentLength: "\(self.outputBuffer.readableBytes)" + ) + self.writeResponse(responseHead, body: self.outputBuffer, context: context) case "/json": - do { - try self.processJSON(context: context) - } catch { - context.close(promise: nil) - } + let jsonResponse = try! self.jsonEncoder.encode(JSONTestResponse()) + self.outputBuffer.clear() + self.outputBuffer.writeBytes(jsonResponse) + let responseHead = self.responseHead( + contentType: "application/json", + contentLength: "\(self.outputBuffer.readableBytes)" + ) + self.writeResponse(responseHead, body: self.outputBuffer, context: context) default: context.close(promise: nil) } - case .body: + case .body, .end: break - case .end: - context.write(self.wrapOutboundOut(.end(nil)), promise: nil) } } - func channelReadComplete(context: ChannelHandlerContext) { - context.flush() - context.fireChannelReadComplete() - } - - private func processPlaintext(context: ChannelHandlerContext) { - let responseHead = self.responseHead(contentType: "text/plain", contentLength: Constants.plainTextResponseLengthString) - context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil) - context.write(self.wrapOutboundOut(.body(.byteBuffer(self.plaintextBuffer))), promise: nil) - } - - private func processJSON(context: ChannelHandlerContext) throws { - let responseHead = self.responseHead(contentType: "application/json", contentLength: Constants.jsonResponseLengthString) - context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil) - self.jsonBuffer.clear() - try self.jsonBuffer.writeBytes(self.jsonEncoder.encode(JSONTestResponse())) - context.write(self.wrapOutboundOut(.body(.byteBuffer(self.jsonBuffer))), promise: nil) + private func writeResponse( + _ head: HTTPResponseHead, body: ByteBuffer, context: ChannelHandlerContext + ) { + context.write(self.wrapOutboundOut(.head(head)), promise: nil) + context.write(self.wrapOutboundOut(.body(.byteBuffer(body))), promise: nil) + context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil) } private func responseHead(contentType: String, contentLength: String) -> HTTPResponseHead { var headers = HTTPHeaders() + headers.reserveCapacity(4) headers.add(name: "content-type", value: contentType) headers.add(name: "content-length", value: contentLength) - headers.add(name: "server", value: Constants.serverName) + headers.add(name: "server", value: "SwiftNIO") headers.add(name: "date", value: self.dateCache.currentTimestamp()) return HTTPResponseHead( - version: Constants.httpVersion, + version: HTTPVersion(major: 1, minor: 1), status: .ok, headers: headers ) @@ -95,13 +77,17 @@ private final class HTTPHandler: ChannelInboundHandler { let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount) let bootstrap = ServerBootstrap(group: group) .serverChannelOption(ChannelOptions.backlog, value: 8192) - .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) + .serverChannelOption( + ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1 + ) .childChannelInitializer { channel in channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: false).flatMap { channel.pipeline.addHandler(HTTPHandler(channel: channel)) } } - .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1) + .childChannelOption( + ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1 + ) .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16) defer { @@ -111,7 +97,9 @@ defer { let channel = try bootstrap.bind(host: "0.0.0.0", port: 8080).wait() guard let localAddress = channel.localAddress else { - fatalError("Address was unable to bind. Please check that the socket was not closed or that the address family was understood.") + fatalError( + "Address was unable to bind. Please check that the socket was not closed or that the address family was understood." + ) } try channel.closeFuture.wait() diff --git a/frameworks/Swift/swift-nio/benchmark_config.json b/frameworks/Swift/swift-nio/benchmark_config.json index 69c74d67124..23558375496 100644 --- a/frameworks/Swift/swift-nio/benchmark_config.json +++ b/frameworks/Swift/swift-nio/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "swift-nio", + "maintainers": ["adam-fowler"], "tests": [{ "default": { "json_url": "/json", diff --git a/frameworks/Swift/swift-nio/swift-nio.dockerfile b/frameworks/Swift/swift-nio/swift-nio.dockerfile index aabc8a12334..3e51cfb8c47 100644 --- a/frameworks/Swift/swift-nio/swift-nio.dockerfile +++ b/frameworks/Swift/swift-nio/swift-nio.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:6.1 AS build +FROM swift:6.2 AS build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:6.1-slim +FROM swift:6.2-slim WORKDIR /run # Install Swift dependencies @@ -31,4 +31,4 @@ COPY --from=build /usr/lib/swift/ /usr/lib/swift/ EXPOSE 8080 -ENTRYPOINT ["./app"] +ENTRYPOINT ["./App"] diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile index d0f44000dc7..c260b41b157 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.1 +FROM oven/bun:1.3 COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile index 1bcc29a8b2f..baca11573ba 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.1 +FROM oven/bun:1.3 COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile index 8f0268556af..79bd03ada81 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.1 +FROM oven/bun:1.3 COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile index 95ad40e9ac8..ab2ac741182 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile index 89ecc3e80a8..32922638026 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod.dockerfile index 0b21155188a..0ca0a0ecc6b 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:24-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/package.json b/frameworks/TypeScript/ditsmod/package.json index 99f331cf416..28da8e9127d 100755 --- a/frameworks/TypeScript/ditsmod/package.json +++ b/frameworks/TypeScript/ditsmod/package.json @@ -23,10 +23,10 @@ }, "devDependencies": { "@types/eslint": "^8.44.2", - "@types/node": "^20.5.7", + "@types/node": "^24", "@typescript-eslint/eslint-plugin": "^6.5.0", "@typescript-eslint/parser": "^6.5.0", - "bun-types": "^1.1.22", + "bun-types": "^1.3", "eslint": "^8.48.0", "prettier": "^3.0.2", "typescript": "^5.2.2" diff --git a/frameworks/TypeScript/nest/.eslintrc.js b/frameworks/TypeScript/nest/.eslintrc.js deleted file mode 100644 index 415cf0888da..00000000000 --- a/frameworks/TypeScript/nest/.eslintrc.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - sourceType: 'module', - }, - plugins: ['@typescript-eslint/eslint-plugin'], - extends: [ - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - 'prettier/@typescript-eslint', - ], - root: true, - env: { - node: true, - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/no-explicit-any': 'off', - }, -}; diff --git a/frameworks/TypeScript/nest/eslint.config.mjs b/frameworks/TypeScript/nest/eslint.config.mjs new file mode 100644 index 00000000000..71c8ac94bd9 --- /dev/null +++ b/frameworks/TypeScript/nest/eslint.config.mjs @@ -0,0 +1,29 @@ +import js from '@eslint/js'; +import tsParser from '@typescript-eslint/parser'; +import tsPlugin from '@typescript-eslint/eslint-plugin'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import globals from 'globals'; + +export default [ + { + ignores: ['dist/**', 'node_modules/**'], + }, + js.configs.recommended, + { + files: ['**/*.ts'], + languageOptions: { + parser: tsParser, + sourceType: 'module', + globals: globals.node, + }, + plugins: { + '@typescript-eslint': tsPlugin, + }, + rules: { + ...tsPlugin.configs.recommended.rules, + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'off', + }, + }, + eslintConfigPrettier, +]; diff --git a/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile b/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile index d55bacee6a7..95d5959ab8e 100644 --- a/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:22-slim COPY ./ ./ diff --git a/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile b/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile index 40b0da005c4..1e010709afc 100644 --- a/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:22-slim COPY ./ ./ diff --git a/frameworks/TypeScript/nest/nestjs-fastify.dockerfile b/frameworks/TypeScript/nest/nestjs-fastify.dockerfile index 485c360794e..05b85bb7ea2 100644 --- a/frameworks/TypeScript/nest/nestjs-fastify.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-fastify.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:22-slim COPY ./ ./ diff --git a/frameworks/TypeScript/nest/nestjs-mongo.dockerfile b/frameworks/TypeScript/nest/nestjs-mongo.dockerfile index a59ac0c9e14..42485e6d142 100644 --- a/frameworks/TypeScript/nest/nestjs-mongo.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-mongo.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:22-slim COPY ./ ./ diff --git a/frameworks/TypeScript/nest/nestjs-mysql.dockerfile b/frameworks/TypeScript/nest/nestjs-mysql.dockerfile index 9ff806b92a8..fc34a5989af 100644 --- a/frameworks/TypeScript/nest/nestjs-mysql.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:22-slim COPY ./ ./ diff --git a/frameworks/TypeScript/nest/nestjs.dockerfile b/frameworks/TypeScript/nest/nestjs.dockerfile index 1ea6fd1581e..3f0410570b6 100644 --- a/frameworks/TypeScript/nest/nestjs.dockerfile +++ b/frameworks/TypeScript/nest/nestjs.dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-slim +FROM node:22-slim COPY ./ ./ diff --git a/frameworks/TypeScript/nest/package.json b/frameworks/TypeScript/nest/package.json index 8b84a7e2ccc..21534aa32f8 100644 --- a/frameworks/TypeScript/nest/package.json +++ b/frameworks/TypeScript/nest/package.json @@ -1,55 +1,63 @@ { "name": "nest", - "version": "0.0.0", + "version": "0.0.1", "description": "NestJS App", "author": "", "license": "MIT", "scripts": { "prebuild": "rimraf dist", - "build": "nest build", + "build": "tsc -p tsconfig.build.json", "format": "prettier --write \"src/**/*.ts\"", - "start": "nest start", - "start:dev": "nest start --watch", - "start:debug": "nest start --debug --watch", + "start": "node dist/main.js", + "start:dev": "ts-node -r tsconfig-paths/register src/main.ts", + "start:debug": "node --inspect -r ts-node/register -r tsconfig-paths/register src/main.ts", "start:prod": "node dist/main.js", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix" }, "dependencies": { - "@nestjs/common": "6.11.11", - "@nestjs/core": "6.11.11", - "@nestjs/platform-express": "6.11.11", - "@nestjs/platform-fastify": "6.11.11", - "@nestjs/typeorm": "7.1.5", - "cache-manager": "3.1.0", - "fastify": "2.15.1", - "fastify-formbody": "3.1.0", - "handlebars": "4.7.7", - "hbs": "4.1.0", - "mongodb": "3.5.4", - "mysql2": "3.9.8", - "pg": "8.5.1", - "point-of-view": "3.7.2", - "reflect-metadata": "0.1.13", - "rimraf": "3.0.2", - "rxjs": "6.5.4", - "typeorm": "0.2.29" + "@fastify/formbody": "^8.0.2", + "@fastify/view": "^11.1.1", + "@nestjs/cache-manager": "^3.0.1", + "@nestjs/common": "^11.1.6", + "@nestjs/core": "^11.1.6", + "@nestjs/platform-express": "^11.1.6", + "@nestjs/platform-fastify": "^11.1.6", + "@nestjs/typeorm": "^11.0.0", + "cache-manager": "^7.2.5", + "fastify": "^5.6.1", + "handlebars": "^4.7.8", + "hbs": "^4.2.0", + "mongodb": "^6.17.0", + "mysql2": "^3.15.0", + "pg": "^8.16.3", + "reflect-metadata": "^0.2.2", + "rimraf": "^6.0.1", + "rxjs": "^7.8.2", + "typeorm": "^0.3.28" }, "devDependencies": { - "@nestjs/cli": "7.5.3", - "@nestjs/schematics": "7.2.4", - "@types/express": "4.17.4", - "@types/express-serve-static-core": "4.17.30", - "@types/node": "18.11.9", - "@typescript-eslint/eslint-plugin": "2.22.0", - "@typescript-eslint/parser": "2.22.0", - "eslint": "6.8.0", - "eslint-config-prettier": "6.10.0", - "eslint-plugin-import": "2.20.1", - "nodemon": "2.0.2", - "prettier": "1.19.1", - "ts-loader": "6.2.1", - "ts-node": "8.6.2", - "tsconfig-paths": "3.9.0", - "typescript": "3.8.3" + "@eslint/js": "^9.35.0", + "@nestjs/cli": "^11.0.10", + "@nestjs/schematics": "^11.0.6", + "@types/express": "^5.0.5", + "@types/express-serve-static-core": "^5.1.0", + "@types/node": "^22.18.6", + "@typescript-eslint/eslint-plugin": "^8.44.1", + "@typescript-eslint/parser": "^8.44.1", + "eslint": "^9.35.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "^2.32.0", + "globals": "^16.4.0", + "nodemon": "^3.1.10", + "prettier": "^3.6.2", + "ts-loader": "^9.5.4", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.9.2" + }, + "overrides": { + "debug": "^4.4.1", + "glob": "^13.0.0", + "string-width": "^4.2.3" } } diff --git a/frameworks/TypeScript/nest/src/database/typeorm-options.ts b/frameworks/TypeScript/nest/src/database/typeorm-options.ts new file mode 100644 index 00000000000..ed035773222 --- /dev/null +++ b/frameworks/TypeScript/nest/src/database/typeorm-options.ts @@ -0,0 +1,49 @@ +import { TypeOrmModuleOptions } from '@nestjs/typeorm'; +import { Fortune as MongoFortune } from '../mongo/fortune.entity'; +import { World as MongoWorld } from '../mongo/world.entity'; +import { Fortune as SqlFortune } from '../sql/fortune.entity'; +import { World as SqlWorld } from '../sql/world.entity'; + +const baseOptions = { + synchronize: false, + logging: false, + host: 'tfb-database', + database: 'hello_world', +} as const; + +export function createTypeOrmOptions(): TypeOrmModuleOptions { + switch (process.env.DATABASE_CONFIGURATION_PROFILE) { + case 'mongodb': + return { + ...baseOptions, + type: 'mongodb', + port: 27017, + entities: [MongoWorld, MongoFortune], + }; + case 'mysql': + return { + ...baseOptions, + type: 'mysql', + port: 3306, + username: 'benchmarkdbuser', + password: 'benchmarkdbpass', + entities: [SqlWorld, SqlFortune], + extra: { + connectionLimit: 30, + }, + }; + case 'postgres': + default: + return { + ...baseOptions, + type: 'postgres', + port: 5432, + username: 'benchmarkdbuser', + password: 'benchmarkdbpass', + entities: [SqlWorld, SqlFortune], + extra: { + max: 30, + }, + }; + } +} diff --git a/frameworks/TypeScript/nest/src/main.ts b/frameworks/TypeScript/nest/src/main.ts index a095bfb746b..6abc290877f 100644 --- a/frameworks/TypeScript/nest/src/main.ts +++ b/frameworks/TypeScript/nest/src/main.ts @@ -5,59 +5,54 @@ import { FastifyAdapter, NestFastifyApplication, } from '@nestjs/platform-fastify'; -import { MongoModule } from './mongo/mongo.module'; import { join } from 'path'; +import cluster from 'node:cluster'; +import os from 'node:os'; +import handlebars from 'handlebars'; +import fastifyView from '@fastify/view'; +import { MongoModule } from './mongo/mongo.module'; import { SqlModule } from './sql/sql.module'; -import cluster from 'cluster' -import os = require('os'); -const port = process.env.PORT || 8080; +const port = Number(process.env.PORT ?? 8080); async function bootstrapExpress() { - let app; - if (process.env.DATABASE_CONFIGURATION_PROFILE === 'mongodb') { - app = await NestFactory.create(MongoModule, { - logger: false, - }); - } else { - app = await NestFactory.create(SqlModule, { - logger: false, - }); - app.getHttpServer().keepAliveTimeout = 0; - } + const appModule = + process.env.DATABASE_CONFIGURATION_PROFILE === 'mongodb' + ? MongoModule + : SqlModule; + const app = await NestFactory.create(appModule, { + logger: false, + }); + app.getHttpServer().keepAliveTimeout = 0; app.setBaseViewsDir(join(__dirname, '..', 'views')); app.setViewEngine('hbs'); Logger.log(`Listening on port ${port}`, 'Nest Express Server'); - return app.listen(port); + await app.listen(port); } async function bootstrapFastify() { - let app; - if (process.env.DATABASE_CONFIGURATION_PROFILE === 'mongodb') { - app = await NestFactory.create( - MongoModule, - new FastifyAdapter(), - { logger: false }, - ); - app.getHttpServer().keepAliveTimeout = 0; - } else { - app = await NestFactory.create( - SqlModule, - new FastifyAdapter(), - { logger: false }, - ); - app.getHttpServer().keepAliveTimeout = 0; - } + const appModule = + process.env.DATABASE_CONFIGURATION_PROFILE === 'mongodb' + ? MongoModule + : SqlModule; + const app = await NestFactory.create( + appModule, + new FastifyAdapter({ logger: false }), + { logger: false }, + ); + app.getHttpServer().keepAliveTimeout = 0; - app.setViewEngine({ + await app.register(fastifyView as never, { engine: { - handlebars: require('handlebars'), + handlebars, }, - templates: join(__dirname, '..', 'views'), + root: join(__dirname, '..', 'views'), }); - await app.listen(8080, '0.0.0.0'); + + await app.listen({ port, host: '0.0.0.0' }); + Logger.log(`Listening on port ${port}`, 'Nest Fastify Server'); } if (cluster.isPrimary) { @@ -73,12 +68,12 @@ if (cluster.isPrimary) { } else { switch (process.env.FRAMEWORK) { case 'fastify': - bootstrapFastify(); + void bootstrapFastify(); Logger.log(`Worker fastify ${process.pid} started`); break; default: - bootstrapExpress(); + void bootstrapExpress(); Logger.log(`Worker express ${process.pid} started`); break; } diff --git a/frameworks/TypeScript/nest/src/mongo/fortune.entity.ts b/frameworks/TypeScript/nest/src/mongo/fortune.entity.ts index b9da71a5408..dc6dbcb50ee 100644 --- a/frameworks/TypeScript/nest/src/mongo/fortune.entity.ts +++ b/frameworks/TypeScript/nest/src/mongo/fortune.entity.ts @@ -1,8 +1,12 @@ import { Column, Entity, ObjectIdColumn } from 'typeorm'; +import { ObjectId } from 'mongodb'; @Entity('fortune') export class Fortune { @ObjectIdColumn() + _id?: ObjectId; + + @Column() id: number; @Column('text') diff --git a/frameworks/TypeScript/nest/src/mongo/mongo.controller.ts b/frameworks/TypeScript/nest/src/mongo/mongo.controller.ts index f39d820e155..32417eca8e1 100644 --- a/frameworks/TypeScript/nest/src/mongo/mongo.controller.ts +++ b/frameworks/TypeScript/nest/src/mongo/mongo.controller.ts @@ -1,5 +1,5 @@ +import { CacheInterceptor } from '@nestjs/cache-manager'; import { - CacheInterceptor, Controller, Get, Header, @@ -28,7 +28,7 @@ export class MongoController { @Get('queries') @Header('Server', 'NestJS') - getMultiQueries(@Query('queries') queries) { + getMultiQueries(@Query('queries') queries?: string) { return this.mongoService.multiQueries(queries); } @@ -41,7 +41,7 @@ export class MongoController { @Get('updates') @Header('Server', 'NestJS') - getUpdates(@Query('queries') queries) { + getUpdates(@Query('queries') queries?: string) { return this.mongoService.updates(queries); } @@ -55,7 +55,7 @@ export class MongoController { @Get('/cached-worlds') @Header('Server', 'NestJS') @UseInterceptors(CacheInterceptor) - getCachedWorlds(@Query('count') count) { + getCachedWorlds(@Query('count') count?: string) { return this.mongoService.cachedWorlds(count); } } diff --git a/frameworks/TypeScript/nest/src/mongo/mongo.module.ts b/frameworks/TypeScript/nest/src/mongo/mongo.module.ts index c0041a6ba7d..8e24bf064d7 100644 --- a/frameworks/TypeScript/nest/src/mongo/mongo.module.ts +++ b/frameworks/TypeScript/nest/src/mongo/mongo.module.ts @@ -1,5 +1,7 @@ -import { CacheModule, Module } from '@nestjs/common'; +import { CacheModule } from '@nestjs/cache-manager'; +import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { createTypeOrmOptions } from '../database/typeorm-options'; import { Fortune } from './fortune.entity'; import { MongoController } from './mongo.controller'; import { MongoService } from './mongo.service'; @@ -7,7 +9,7 @@ import { World } from './world.entity'; @Module({ imports: [ - TypeOrmModule.forRoot(), + TypeOrmModule.forRoot(createTypeOrmOptions()), TypeOrmModule.forFeature([World, Fortune]), CacheModule.register(), ], diff --git a/frameworks/TypeScript/nest/src/mongo/mongo.service.ts b/frameworks/TypeScript/nest/src/mongo/mongo.service.ts index 3743bcae2f7..31712cd5ffb 100644 --- a/frameworks/TypeScript/nest/src/mongo/mongo.service.ts +++ b/frameworks/TypeScript/nest/src/mongo/mongo.service.ts @@ -15,19 +15,12 @@ export class MongoService { singleQuery() { const rand = Math.floor(Math.random() * 10000) + 1; - return this.worldRepository.findOne({ id: rand }); + return this.worldRepository.findOneBy({ id: rand }); } - async multiQueries(queries: string) { - const number = Math.min(Math.max(parseInt(queries) || 1, 1), 500); - const promisesArray = []; - - for (let i = 0; i < number; i++) { - promisesArray.push(this.singleQuery()); - } - - const worlds = await Promise.all(promisesArray); - return worlds; + async multiQueries(queries?: string) { + const number = this.parseQueryCount(queries); + return Promise.all(Array.from({ length: number }, () => this.singleQuery())); } async fortunes() { @@ -41,15 +34,15 @@ export class MongoService { return { fortunes: allFortunes }; } - async updates(queries) { - const number = Math.min(Math.max(parseInt(queries) || 1, 1), 500); - const worlds = []; + async updates(queries?: string) { + const number = this.parseQueryCount(queries); const bulk = this.worldRepository.initializeUnorderedBulkOp(); + const worlds = await Promise.all( + Array.from({ length: number }, () => this.singleQuery()), + ); - for (let i = 0; i < number; i++) { - const worldToUpdate = await this.singleQuery(); + for (const worldToUpdate of worlds) { worldToUpdate.randomNumber = Math.floor(Math.random() * 10000) + 1; - worlds.push(worldToUpdate); bulk .find({ id: worldToUpdate.id }) .update({ $set: { randomNumber: worldToUpdate.randomNumber } }); @@ -59,14 +52,12 @@ export class MongoService { return worlds; } - async cachedWorlds(count) { - const number = Math.min(Math.max(parseInt(count) || 1, 1), 500); - const promisesArray = []; - for (let i = 0; i < number; i++) { - promisesArray.push(this.singleQuery()); - } + async cachedWorlds(count?: string) { + const number = this.parseQueryCount(count); + return Promise.all(Array.from({ length: number }, () => this.singleQuery())); + } - const worlds = await Promise.all(promisesArray); - return worlds; + private parseQueryCount(value?: string) { + return Math.min(Math.max(Number.parseInt(value ?? '', 10) || 1, 1), 500); } } diff --git a/frameworks/TypeScript/nest/src/mongo/world.entity.ts b/frameworks/TypeScript/nest/src/mongo/world.entity.ts index b1f1b1090fa..55acd05e08b 100644 --- a/frameworks/TypeScript/nest/src/mongo/world.entity.ts +++ b/frameworks/TypeScript/nest/src/mongo/world.entity.ts @@ -1,8 +1,12 @@ import { Column, Entity, ObjectIdColumn } from 'typeorm'; +import { ObjectId } from 'mongodb'; @Entity('world') export class World { @ObjectIdColumn() + _id?: ObjectId; + + @Column() id: number; @Column() diff --git a/frameworks/TypeScript/nest/src/sql/sql.controller.ts b/frameworks/TypeScript/nest/src/sql/sql.controller.ts index 08f0ccc671e..8668f957d20 100644 --- a/frameworks/TypeScript/nest/src/sql/sql.controller.ts +++ b/frameworks/TypeScript/nest/src/sql/sql.controller.ts @@ -1,5 +1,5 @@ +import { CacheInterceptor } from '@nestjs/cache-manager'; import { - CacheInterceptor, Controller, Get, Header, @@ -28,7 +28,7 @@ export class SqlController { @Get('queries') @Header('Server', 'NestJS') - getMultiQueries(@Query('queries') queries) { + getMultiQueries(@Query('queries') queries?: string) { return this.sqlService.multiQueries(queries); } @@ -41,7 +41,7 @@ export class SqlController { @Get('updates') @Header('Server', 'NestJS') - getUpdates(@Query('queries') queries) { + getUpdates(@Query('queries') queries?: string) { return this.sqlService.updates(queries); } @@ -55,7 +55,7 @@ export class SqlController { @Get('/cached-worlds') @Header('Server', 'NestJS') @UseInterceptors(CacheInterceptor) - getCachedWorlds(@Query('count') count) { + getCachedWorlds(@Query('count') count?: string) { return this.sqlService.cachedWorlds(count); } } diff --git a/frameworks/TypeScript/nest/src/sql/sql.module.ts b/frameworks/TypeScript/nest/src/sql/sql.module.ts index 17b83258650..14f2a36b0ec 100644 --- a/frameworks/TypeScript/nest/src/sql/sql.module.ts +++ b/frameworks/TypeScript/nest/src/sql/sql.module.ts @@ -1,5 +1,7 @@ -import { CacheModule, Module } from '@nestjs/common'; +import { CacheModule } from '@nestjs/cache-manager'; +import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { createTypeOrmOptions } from '../database/typeorm-options'; import { Fortune } from './fortune.entity'; import { SqlController } from './sql.controller'; import { SqlService } from './sql.service'; @@ -7,7 +9,7 @@ import { World } from './world.entity'; @Module({ imports: [ - TypeOrmModule.forRoot(), + TypeOrmModule.forRoot(createTypeOrmOptions()), TypeOrmModule.forFeature([World, Fortune]), CacheModule.register(), ], diff --git a/frameworks/TypeScript/nest/src/sql/sql.service.ts b/frameworks/TypeScript/nest/src/sql/sql.service.ts index 7c40282ea4c..088d6419d50 100644 --- a/frameworks/TypeScript/nest/src/sql/sql.service.ts +++ b/frameworks/TypeScript/nest/src/sql/sql.service.ts @@ -15,19 +15,12 @@ export class SqlService { singleQuery() { const rand = Math.floor(Math.random() * 10000) + 1; - return this.worldRepository.findOne(rand); + return this.worldRepository.findOneBy({ id: rand }); } - async multiQueries(queries: string) { - const number = Math.min(Math.max(parseInt(queries) || 1, 1), 500); - const promisesArray = []; - - for (let i = 0; i < number; i++) { - promisesArray.push(this.singleQuery()); - } - - const worlds = await Promise.all(promisesArray); - return worlds; + async multiQueries(queries?: string) { + const number = this.parseQueryCount(queries); + return Promise.all(Array.from({ length: number }, () => this.singleQuery())); } async fortunes() { @@ -41,34 +34,30 @@ export class SqlService { return { fortunes: allFortunes }; } - async updates(queries) { - const number = Math.min(Math.max(parseInt(queries) || 1, 1), 500); - const worlds = []; - const promisesArray = []; + async updates(queries?: string) { + const number = this.parseQueryCount(queries); + const worlds = await Promise.all( + Array.from({ length: number }, () => this.singleQuery()), + ); + + await Promise.all( + worlds.map((world) => { + world.randomnumber = Math.floor(Math.random() * 10000) + 1; + return this.worldRepository.update(world.id, { + randomnumber: world.randomnumber, + }); + }), + ); - for (let i = 0; i < number; i++) { - const worldToUpdate = await this.singleQuery(); - worldToUpdate.randomnumber = Math.floor(Math.random() * 10000) + 1; - worlds.push(worldToUpdate); - promisesArray.push( - this.worldRepository.update(worldToUpdate.id, { - randomnumber: worldToUpdate.randomnumber, - }), - ); - } - - await Promise.all(promisesArray); return worlds; } - async cachedWorlds(count) { - const number = Math.min(Math.max(parseInt(count) || 1, 1), 500); - const promisesArray = []; - for (let i = 0; i < number; i++) { - promisesArray.push(this.singleQuery()); - } + async cachedWorlds(count?: string) { + const number = this.parseQueryCount(count); + return Promise.all(Array.from({ length: number }, () => this.singleQuery())); + } - const worlds = await Promise.all(promisesArray); - return worlds; + private parseQueryCount(value?: string) { + return Math.min(Math.max(Number.parseInt(value ?? '', 10) || 1, 1), 500); } } diff --git a/frameworks/TypeScript/nest/src/sql/world.entity.ts b/frameworks/TypeScript/nest/src/sql/world.entity.ts index c237d5e197b..560d432cda3 100644 --- a/frameworks/TypeScript/nest/src/sql/world.entity.ts +++ b/frameworks/TypeScript/nest/src/sql/world.entity.ts @@ -3,8 +3,8 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; @Entity('world') export class World { @PrimaryGeneratedColumn() - id: number; + id!: number; @Column() - randomnumber: number; + randomnumber!: number; } diff --git a/frameworks/TypeScript/nest/tsconfig.json b/frameworks/TypeScript/nest/tsconfig.json index d35e11cf7bd..9bd8696970f 100644 --- a/frameworks/TypeScript/nest/tsconfig.json +++ b/frameworks/TypeScript/nest/tsconfig.json @@ -5,13 +5,14 @@ "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es2017", + "target": "es2021", "sourceMap": true, "outDir": "./dist", "baseUrl": "./", "incremental": true, "skipLibCheck": true, - "esModuleInterop": true + "esModuleInterop": true, + "moduleResolution": "node" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] diff --git a/frameworks/TypeScript/nextjs/nextjs.dockerfile b/frameworks/TypeScript/nextjs/nextjs.dockerfile index 9f68f27e4b1..250adc923b9 100644 --- a/frameworks/TypeScript/nextjs/nextjs.dockerfile +++ b/frameworks/TypeScript/nextjs/nextjs.dockerfile @@ -1,4 +1,4 @@ -FROM node:22-slim +FROM node:24-slim ENV NEXT_TELEMETRY_DISABLED="1" ENV DATABASE_URL="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world" diff --git a/frameworks/TypeScript/nextjs/package-lock.json b/frameworks/TypeScript/nextjs/package-lock.json index 68185dc81d0..b8eb9d55023 100644 --- a/frameworks/TypeScript/nextjs/package-lock.json +++ b/frameworks/TypeScript/nextjs/package-lock.json @@ -8,38 +8,45 @@ "name": "next-techempower-benchmarks", "version": "0.1.0", "dependencies": { - "kysely": "^0.27.5", - "next": "^15.2.4", - "pg": "^8.13.1", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "kysely": "^0.27.6", + "next": "15.3.3", + "pg": "^8.16.3", + "react": "19.2.3", + "react-dom": "19.2.3" }, "devDependencies": { - "@types/node": "^20", - "@types/pg": "^8.11.10", + "@types/node": "^24", + "@types/pg": "^8.11", "@types/react": "^19", "@types/react-dom": "^19", "typescript": "^5" } }, "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", - "license": "MIT", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "optional": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], - "license": "Apache-2.0", "optional": true, "os": [ "darwin" @@ -51,17 +58,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", "cpu": [ "x64" ], - "license": "Apache-2.0", "optional": true, "os": [ "darwin" @@ -73,17 +79,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -93,13 +98,12 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "darwin" @@ -109,13 +113,12 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", "cpu": [ "arm" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -125,13 +128,42 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], "optional": true, "os": [ "linux" @@ -141,13 +173,12 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", "cpu": [ "s390x" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -157,13 +188,12 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -173,13 +203,12 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", "cpu": [ "arm64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -189,13 +218,12 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", "cpu": [ "x64" ], - "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" @@ -205,13 +233,12 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", "cpu": [ "arm" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -223,17 +250,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" + "@img/sharp-libvips-linux-arm": "1.2.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", "cpu": [ "arm64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -245,17 +271,58 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", "cpu": [ "s390x" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -267,17 +334,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", "cpu": [ "x64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -289,17 +355,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" + "@img/sharp-libvips-linux-x64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", "cpu": [ "arm64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -311,17 +376,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", "cpu": [ "x64" ], - "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -333,21 +397,38 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", "cpu": [ "wasm32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.2.0" + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -356,13 +437,12 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", "cpu": [ "ia32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" @@ -375,13 +455,12 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" @@ -394,19 +473,17 @@ } }, "node_modules/@next/env": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.2.4.tgz", - "integrity": "sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==", - "license": "MIT" + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.3.tgz", + "integrity": "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==" }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.4.tgz", - "integrity": "sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz", + "integrity": "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -416,13 +493,12 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz", - "integrity": "sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz", + "integrity": "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -432,13 +508,12 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz", - "integrity": "sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz", + "integrity": "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -448,13 +523,12 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz", - "integrity": "sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz", + "integrity": "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -464,13 +538,12 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz", - "integrity": "sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz", + "integrity": "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -480,13 +553,12 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz", - "integrity": "sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz", + "integrity": "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -496,13 +568,12 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz", - "integrity": "sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz", + "integrity": "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -512,13 +583,12 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz", - "integrity": "sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz", + "integrity": "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -530,8 +600,7 @@ "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "license": "Apache-2.0" + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" }, "node_modules/@swc/helpers": { "version": "0.5.15", @@ -543,87 +612,23 @@ } }, "node_modules/@types/node": { - "version": "20.17.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.11.tgz", - "integrity": "sha512-Ept5glCK35R8yeyIeYlRIZtX6SLRyqMhOFTgj5SOkMpLTdw3SEHI9fHx60xaUZ+V1aJxQJODE+7/j5ocZydYTg==", + "version": "24.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", + "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "dev": true, - "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~7.16.0" } }, "node_modules/@types/pg": { - "version": "8.11.10", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.10.tgz", - "integrity": "sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "pg-protocol": "*", - "pg-types": "^4.0.1" - } - }, - "node_modules/@types/pg/node_modules/pg-types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", - "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", - "dev": true, - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "pg-numeric": "1.0.2", - "postgres-array": "~3.0.1", - "postgres-bytea": "~3.0.0", - "postgres-date": "~2.1.0", - "postgres-interval": "^3.0.0", - "postgres-range": "^1.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@types/pg/node_modules/postgres-array": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", - "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/@types/pg/node_modules/postgres-bytea": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", - "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "obuf": "~1.1.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/pg/node_modules/postgres-date": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", - "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/@types/pg/node_modules/postgres-interval": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", - "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "pg-types": "^2.2.0" } }, "node_modules/@types/react": { @@ -683,51 +688,6 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "optional": true - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -736,27 +696,18 @@ "license": "MIT" }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "optional": true, "engines": { "node": ">=8" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT", - "optional": true - }, "node_modules/kysely": { - "version": "0.27.5", - "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.5.tgz", - "integrity": "sha512-s7hZHcQeSNKpzCkHRm8yA+0JPLjncSWnjb+2TIElwS2JAqYr+Kv3Ess+9KFfJS0C1xcQ1i9NkNHpWwCYpHMWsA==", - "license": "MIT", + "version": "0.27.6", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", + "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", "engines": { "node": ">=14.0.0" } @@ -780,12 +731,12 @@ } }, "node_modules/next": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/next/-/next-15.2.4.tgz", - "integrity": "sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==", - "license": "MIT", + "version": "15.3.3", + "resolved": "https://registry.npmjs.org/next/-/next-15.3.3.tgz", + "integrity": "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==", + "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details.", "dependencies": { - "@next/env": "15.2.4", + "@next/env": "15.3.3", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -800,15 +751,15 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.2.4", - "@next/swc-darwin-x64": "15.2.4", - "@next/swc-linux-arm64-gnu": "15.2.4", - "@next/swc-linux-arm64-musl": "15.2.4", - "@next/swc-linux-x64-gnu": "15.2.4", - "@next/swc-linux-x64-musl": "15.2.4", - "@next/swc-win32-arm64-msvc": "15.2.4", - "@next/swc-win32-x64-msvc": "15.2.4", - "sharp": "^0.33.5" + "@next/swc-darwin-arm64": "15.3.3", + "@next/swc-darwin-x64": "15.3.3", + "@next/swc-linux-arm64-gnu": "15.3.3", + "@next/swc-linux-arm64-musl": "15.3.3", + "@next/swc-linux-x64-gnu": "15.3.3", + "@next/swc-linux-x64-musl": "15.3.3", + "@next/swc-win32-arm64-msvc": "15.3.3", + "@next/swc-win32-x64-msvc": "15.3.3", + "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -833,30 +784,22 @@ } } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" - }, "node_modules/pg": { - "version": "8.13.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", - "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", - "license": "MIT", + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "dependencies": { - "pg-connection-string": "^2.7.0", - "pg-pool": "^3.7.0", - "pg-protocol": "^1.7.0", - "pg-types": "^2.1.0", - "pgpass": "1.x" + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 16.0.0" }, "optionalDependencies": { - "pg-cloudflare": "^1.1.1" + "pg-cloudflare": "^1.2.7" }, "peerDependencies": { "pg-native": ">=3.0.1" @@ -868,17 +811,15 @@ } }, "node_modules/pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "license": "MIT", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", "optional": true }, "node_modules/pg-connection-string": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", - "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", - "license": "MIT" + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==" }, "node_modules/pg-int8": { "version": "1.0.1", @@ -889,30 +830,18 @@ "node": ">=4.0.0" } }, - "node_modules/pg-numeric": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", - "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, "node_modules/pg-pool": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", - "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", - "license": "MIT", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-protocol": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", - "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==", - "license": "MIT" + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==" }, "node_modules/pg-types": { "version": "2.2.0", @@ -1012,45 +941,34 @@ "node": ">=0.10.0" } }, - "node_modules/postgres-range": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", - "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", - "dev": true, - "license": "MIT" - }, "node_modules/react": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", - "license": "MIT", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", - "license": "MIT", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "dependencies": { - "scheduler": "^0.25.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.0.0" + "react": "^19.2.3" } }, "node_modules/scheduler": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", - "license": "MIT" + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "optional": true, "bin": { "semver": "bin/semver.js" @@ -1060,16 +978,15 @@ } }, "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, - "license": "Apache-2.0", "optional": true, "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -1078,35 +995,30 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", - "optional": true, - "dependencies": { - "is-arrayish": "^0.3.1" + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" } }, "node_modules/source-map-js": { @@ -1179,11 +1091,10 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, - "license": "MIT" + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true }, "node_modules/xtend": { "version": "4.0.2", diff --git a/frameworks/TypeScript/nextjs/package.json b/frameworks/TypeScript/nextjs/package.json index d1e98eb62e3..12667c74a8f 100644 --- a/frameworks/TypeScript/nextjs/package.json +++ b/frameworks/TypeScript/nextjs/package.json @@ -4,20 +4,20 @@ "private": true, "scripts": { "dev": "next dev --turbopack", - "build": "next build", + "build": "next build --turbopack", "start": "next start", "lint": "next lint" }, "dependencies": { - "kysely": "^0.27.5", - "next": "^15.2.4", - "pg": "^8.13.1", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "kysely": "^0.27.6", + "next": "15.3.3", + "pg": "^8.16.3", + "react": "19.2.3", + "react-dom": "19.2.3" }, "devDependencies": { - "@types/node": "^20", - "@types/pg": "^8.11.10", + "@types/node": "^24", + "@types/pg": "^8.11", "@types/react": "^19", "@types/react-dom": "^19", "typescript": "^5" diff --git a/frameworks/TypeScript/typescript-rest/benchmark_config.json b/frameworks/TypeScript/typescript-rest/benchmark_config.json deleted file mode 100644 index a347afdb4ad..00000000000 --- a/frameworks/TypeScript/typescript-rest/benchmark_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "framework": "typescript-rest", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "update_url": "/updates?queries=", - "query_url": "/queries?queries=", - "db_url": "/db", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "framework": "express", - "platform": "NodeJS", - "language": "TypeScript", - "flavor": "NodeJS", - "os": "Linux", - "orm": "Full", - "database": "Postgres", - "database_os": "Linux", - "display_name": "typescript-rest", - "versus": "nodejs", - "tags": ["broken"] - } - } - ] -} diff --git a/frameworks/TypeScript/typescript-rest/config.toml b/frameworks/TypeScript/typescript-rest/config.toml deleted file mode 100644 index 3465a9cf588..00000000000 --- a/frameworks/TypeScript/typescript-rest/config.toml +++ /dev/null @@ -1,18 +0,0 @@ -[framework] -name = "typescript-rest" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "NodeJS" -versus = "nodejs" -webserver = "None" diff --git a/frameworks/TypeScript/typescript-rest/nodemon.json b/frameworks/TypeScript/typescript-rest/nodemon.json deleted file mode 100644 index e804b3ee3f9..00000000000 --- a/frameworks/TypeScript/typescript-rest/nodemon.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "ignore": [ - ".git", - "node_modules" - ], - "watch": [ - "." - ], - "events": { - "restart": "fuser -k 3000/tcp" - }, - "exec": "ts-node ./src/index.ts", - "ext": "ts" -} diff --git a/frameworks/TypeScript/typescript-rest/package.json b/frameworks/TypeScript/typescript-rest/package.json deleted file mode 100644 index f549336bc0f..00000000000 --- a/frameworks/TypeScript/typescript-rest/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "typescript-rest", - "version": "1.0.0", - "scripts": { - "dev": "nodemon --delay 1500ms", - "lint": "tslint -p tsconfig.json", - "start": "ts-node -r tsconfig-paths/register src/index.ts" - }, - "dependencies": { - "express": "^4.16.3", - "knex": "^0.15.2", - "objection": "^1.3.0", - "pg": "^7.5.0", - "typescript-rest": "^1.7.0" - }, - "devDependencies": { - "@types/express": "^4.16.0", - "@types/knex": "^0.14.26", - "@types/node": "^10.11.6", - "@types/pg": "^7.4.11", - "nodemon": "^1.18.4", - "ts-node": "^7.0.1", - "tsconfig-paths": "^3.6.0", - "tslint": "^5.11.0", - "tslint-config-airbnb": "^5.11.0", - "typescript": "^3.1.2" - } -} diff --git a/frameworks/TypeScript/typescript-rest/src/config/Knexfile.ts b/frameworks/TypeScript/typescript-rest/src/config/Knexfile.ts deleted file mode 100644 index 776073fe3ec..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/config/Knexfile.ts +++ /dev/null @@ -1,12 +0,0 @@ -// tslint:disable:max-line-length -import { Config, PoolConfig } from "knex"; - -const client: string = "pg"; // can also be "postgresql" -const pool: Readonly = { min: 2, max: 10 }; -const connection: string = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world"; - -export default { - client, - connection, - pool, -}; diff --git a/frameworks/TypeScript/typescript-rest/src/controllers/db.ts b/frameworks/TypeScript/typescript-rest/src/controllers/db.ts deleted file mode 100644 index 3526d958fbd..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/controllers/db.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { GET, Path } from "typescript-rest"; - -import randomNumber from "../helpers/randomNumber"; -import World from "../models/world"; - -@Path("/db") -export default class SingleQuery { - /** - * Implements the `Single query` test type. - */ - - @GET - async singleQuery(): Promise { - const id: number = randomNumber(); - const world: World = await World - .query() - .findById(id) - .throwIfNotFound(); - - return world; - } -} diff --git a/frameworks/TypeScript/typescript-rest/src/controllers/json.ts b/frameworks/TypeScript/typescript-rest/src/controllers/json.ts deleted file mode 100644 index ff2620b0d33..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/controllers/json.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { GET, Path } from "typescript-rest"; - -interface IResult { - message: string; -} - -@Path("/json") -export default class Json { - /** - * Implements the `JSON Serialization` test type. Under - * the hood, Express should have serialized the result - * with `res.json`. - */ - - @GET - json(): IResult { - return { message: "Hello, World!" }; - } -} diff --git a/frameworks/TypeScript/typescript-rest/src/controllers/plaintext.ts b/frameworks/TypeScript/typescript-rest/src/controllers/plaintext.ts deleted file mode 100644 index 6a1a6a3e3f3..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/controllers/plaintext.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as express from "express"; -import { ContextResponse, GET, Path } from "typescript-rest"; - -@Path("/plaintext") -export default class Plaintext { - /** - * Implements the `Plaintext` test type. - */ - - @GET - plaintext(@ContextResponse response: express.Response): string { - response.contentType("text/plain"); // defaults to `text/html` for this function - return "Hello, World!"; - } -} diff --git a/frameworks/TypeScript/typescript-rest/src/controllers/queries.ts b/frameworks/TypeScript/typescript-rest/src/controllers/queries.ts deleted file mode 100644 index dbef9e81dbb..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/controllers/queries.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { GET, Path, QueryParam } from "typescript-rest"; - -import randomNumber from "../helpers/randomNumber"; -import sanitizeQueries from "../helpers/sanitizeQueries"; - -import World from "../models/world"; - -@Path("/queries") -export default class MultipleQueries { - /** - * Implements the `Multiple queries` test type. - */ - - @GET - async multipleQueries(@QueryParam("queries") queries: string): Promise { - const length: number = sanitizeQueries(queries); - const worlds: World[] = []; - - // Use a for-loop here because Array.from is just not - // performant at all, but is really nice. - // https://jsbench.me/ntjn3s2t0y/1 - for (let i = 0; i < length; i += 1) { - const id: number = randomNumber(); - const world: World = await World.query().findById(id).throwIfNotFound(); - worlds.push(world); - } - - return worlds; - } -} diff --git a/frameworks/TypeScript/typescript-rest/src/controllers/updates.ts b/frameworks/TypeScript/typescript-rest/src/controllers/updates.ts deleted file mode 100644 index f58b48375d4..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/controllers/updates.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { QueryBuilder } from "objection"; -import { GET, Path, QueryParam } from "typescript-rest"; - -import randomNumber from "../helpers/randomNumber"; -import sanitizeQueries from "../helpers/sanitizeQueries"; - -import World from "../models/world"; - -@Path("/updates") -export default class DataUpdates { - /** - * Implements the `Data updates` test type. - */ - - @GET - async dataUpdates(@QueryParam("queries") queries: string): Promise { - const length: number = sanitizeQueries(queries); - const worlds: QueryBuilder[] = []; - - for (let i = 0; i < length; i += 1) { - const id: number = randomNumber(); - worlds.push( - World - .query() - .patch({ randomnumber: randomNumber() }) - .findById(id) - .returning("*") - .throwIfNotFound() - ); - } - - return Promise.all(worlds); - } -} diff --git a/frameworks/TypeScript/typescript-rest/src/helpers/defaultTo.ts b/frameworks/TypeScript/typescript-rest/src/helpers/defaultTo.ts deleted file mode 100644 index 9a358c0611d..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/helpers/defaultTo.ts +++ /dev/null @@ -1,24 +0,0 @@ -// tslint:disable:max-line-length - -/** - * Returns the second argument if it is not `null`, `NaN`, - * or `undefined`; otherwise the first argument is returned. - * Arguments must be the same type. This function is not - * curried, so all arguments must be supplied at once. - * - * @function - * @sig a -> b -> a | b - * @param {a} def The default value. - * @param {b} val The value returned instead of `def` unles `val` is `null`, `NaN`, or `undefined` - * @return {a|b} The second value if it is not `null`, `NaN`, or `undefined`, otherwise the default value - * @example - * - * const port = defaultTo(3000, +process.env.PORT); - */ - -export default function(def: T, val: T): T { - return val == null // handles `null` and `undefined` - || val !== val // handles NaN - ? def - : val; -} diff --git a/frameworks/TypeScript/typescript-rest/src/helpers/randomNumber.ts b/frameworks/TypeScript/typescript-rest/src/helpers/randomNumber.ts deleted file mode 100644 index 2b751ad2373..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/helpers/randomNumber.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Generates a random number between 1 and 10000 - * - * @function - * @returns {*} A number between 1 and 10000 - * Math.floor(Math.random() * 10000) + 1} - */ - -export default function (): number { - const max = 10000; - return truncate((Math.random() * max) + 1); -} - -function truncate(n: number): number { - return n | 0; -} diff --git a/frameworks/TypeScript/typescript-rest/src/helpers/sanitizeQueries.ts b/frameworks/TypeScript/typescript-rest/src/helpers/sanitizeQueries.ts deleted file mode 100644 index 6da1b79cba5..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/helpers/sanitizeQueries.ts +++ /dev/null @@ -1,21 +0,0 @@ -import defaultTo from "./defaultTo"; - -/** - * Provides an upper limit on queries. - * - * @function - * @sig a -> b - * @param {a} queries A string representation of a number. - * @returns {1..500|n} A number-casted version of the provided string between 1 and 500. - */ - -export default function (queries: string): number { - const int = defaultTo(1, parseInt(queries, undefined)); - const max = 500; - const min = 1; - - if (int > max) { return max; } - if (int < min) { return min; } - - return int; -} diff --git a/frameworks/TypeScript/typescript-rest/src/index.ts b/frameworks/TypeScript/typescript-rest/src/index.ts deleted file mode 100644 index 8a61b831b8a..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as cluster from "cluster"; -import * as os from "os"; -import Server from "./server"; - -if (cluster.isMaster) { - const cpuCount: os.CpuInfo[] = os.cpus(); - - for (const cpu of cpuCount) { - cluster.fork(); - } - - cluster.on("exit", () => { - process.exit(1); - }); -} else { - new Server().start(); -} diff --git a/frameworks/TypeScript/typescript-rest/src/models/world.ts b/frameworks/TypeScript/typescript-rest/src/models/world.ts deleted file mode 100644 index 189b971478f..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/models/world.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Model } from "objection"; - -export default class World extends Model { - static tableName: string = "world"; - - readonly id: number; - randomnumber: number; -} diff --git a/frameworks/TypeScript/typescript-rest/src/server.ts b/frameworks/TypeScript/typescript-rest/src/server.ts deleted file mode 100644 index fe0d48e4ff4..00000000000 --- a/frameworks/TypeScript/typescript-rest/src/server.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as express from "express"; -import * as Knex from "knex"; -import { Model } from "objection"; -import { Server } from "typescript-rest"; - -import Knexfile from "./config/Knexfile"; -import defaultTo from "./helpers/defaultTo"; - -import Plaintext from "./controllers/plaintext"; -import Json from "./controllers/json"; -import SingleQuery from "./controllers/db"; -import MultipleQueries from "./controllers/queries"; -import DataUpdates from "./controllers/updates"; - -const DEFAULT_PORT = 3000; -// @ts-ignore - process.env.PORT may be undefined, and -// that's the point. -const PORT = defaultTo(DEFAULT_PORT, +process.env.PORT); - -export default class ApiServer { - private readonly app: express.Application; - - constructor() { - this.app = express(); - this.app.set("etag", false); // unsets the defaulted Etag header - this.app.set("x-powered-by", false); // unsets the defaulted X-Powered-By header - - this.config(); - - Server.buildServices( - this.app, - Plaintext, - Json, - SingleQuery, - MultipleQueries, - DataUpdates - ); - } - - private config(): void { - // Sets the global header `Server` as a middleware. We - // are intentionally receiving and ignoring the `req` - // parameter, indicated by the underscore. - this.app.use((_, res, next): void => { - res.set("Server", "TypeScript-rest"); - - next(); - }); - - // Initiatlize connection to the database and connect - // the knex query builder to our objection models. - const knex = Knex(Knexfile); - Model.knex(knex); - } - - start(): void { - this.app.listen(PORT, (err: any) => { - if (err) { - throw err; - } - - console.info(`Server listening on port ${PORT}`); - }); - } -} diff --git a/frameworks/TypeScript/typescript-rest/tsconfig.json b/frameworks/TypeScript/typescript-rest/tsconfig.json deleted file mode 100644 index 951dbd43675..00000000000 --- a/frameworks/TypeScript/typescript-rest/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "moduleResolution": "node", - "strictNullChecks": true, - "noImplicitAny": true, - "noImplicitReturns": true, - "noImplicitThis": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "baseUrl": "./src", - "typeRoots": [ - "./node_modules/@types" - ] - }, - "include": [ - "**/**.ts" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/frameworks/TypeScript/typescript-rest/tslint.json b/frameworks/TypeScript/typescript-rest/tslint.json deleted file mode 100644 index cf3a82ae341..00000000000 --- a/frameworks/TypeScript/typescript-rest/tslint.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "tslint-config-airbnb", - "rules": { - "import-name": false, - "no-magic-numbers": true, - "quotemark": [true, "double"], - "semicolon": true, - "trailing-comma": [true, { - "singleline": "never", - "multiline": { "functions": "never" } - } - ] - } -} diff --git a/frameworks/TypeScript/typescript-rest/typescript-rest.dockerfile b/frameworks/TypeScript/typescript-rest/typescript-rest.dockerfile deleted file mode 100644 index 9e949a9acfc..00000000000 --- a/frameworks/TypeScript/typescript-rest/typescript-rest.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM node:10 - -WORKDIR /home -COPY . . - -ENV PORT 8080 - -RUN rm -rf node_modules/ -RUN yarn install --pure-lockfile - -EXPOSE 8080 - -CMD ["yarn", "start"] diff --git a/frameworks/Zig/dusty/.gitignore b/frameworks/Zig/dusty/.gitignore new file mode 100644 index 00000000000..d8c8979f82c --- /dev/null +++ b/frameworks/Zig/dusty/.gitignore @@ -0,0 +1,2 @@ +.zig-cache +zig-out diff --git a/frameworks/Zig/dusty/README.md b/frameworks/Zig/dusty/README.md new file mode 100644 index 00000000000..df1b2b944ff --- /dev/null +++ b/frameworks/Zig/dusty/README.md @@ -0,0 +1,25 @@ + +# [Dusty](https://github.com/lalinsky/dusty) - Zig HTTP client/server library + +## Description + +Zig HTTP client/server library built on top of zio (coroutine/async engine) + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:3000/json + +### Test 2: Plaintext + + http://localhost:3000/plaintext + +### Test 2: Single Row Query + + http://localhost:3000/db + +### Test 4: Fortunes (Template rendering) + + http://localhost:3000/fortunes + diff --git a/frameworks/Zig/dusty/benchmark_config.json b/frameworks/Zig/dusty/benchmark_config.json new file mode 100644 index 00000000000..a34aa4c3d46 --- /dev/null +++ b/frameworks/Zig/dusty/benchmark_config.json @@ -0,0 +1,27 @@ +{ + "framework": "dusty", + "maintainers": ["dragosv"], + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "port": 3000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "dusty", + "language": "Zig", + "flavor": "None", + "orm": "raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Dusty (Zig)", + "notes": "", + "versus": "" + } + }] +} diff --git a/frameworks/Zig/dusty/build.zig b/frameworks/Zig/dusty/build.zig new file mode 100644 index 00000000000..794a04d7b13 --- /dev/null +++ b/frameworks/Zig/dusty/build.zig @@ -0,0 +1,58 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const dep_opts = .{ .target = target, .optimize = optimize }; + + const root_module = b.addModule("root_mod", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("src/main.zig"), + }); + + const dusty_dep = b.dependency("dusty", dep_opts); + const dusty_module = dusty_dep.module("dusty"); + const zio_module = dusty_dep.builder.dependency("zio", dep_opts).module("zio"); + const pg_module = b.dependency("pg", dep_opts).module("pg"); + const datetimez_module = b.dependency("datetimez", dep_opts).module("datetime"); + + const exe = b.addExecutable(.{ + .name = "dusty", + .root_module = root_module, + }); + + exe.root_module.addImport("dusty", dusty_module); + exe.root_module.addImport("zio", zio_module); + exe.root_module.addImport("pg", pg_module); + exe.root_module.addImport("datetimez", datetimez_module); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/frameworks/Zig/dusty/build.zig.zon b/frameworks/Zig/dusty/build.zig.zon new file mode 100644 index 00000000000..cd25187bc91 --- /dev/null +++ b/frameworks/Zig/dusty/build.zig.zon @@ -0,0 +1,24 @@ +.{ + .name = .dusty_testing, + .fingerprint = 0x402c0022f1133ce0, + .version = "0.1.1", + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, + .dependencies = .{ + .pg = .{ + .url = "git+https://github.com/karlseguin/pg.zig.git#f8d4892387fbad2abdf775783e101e50a7114335", + .hash = "pg-0.0.0-Wp_7gag6BgD_QAZrPhNNEGpnUZR_LEkKT40Ura3p-4yX", + }, + .dusty = .{ + .url = "git+https://github.com/lalinsky/dusty.git#8aaedf71a069758bd88437d117ccd89069dc9bf8", + .hash = "dusty-0.0.0-Qdw7Rqh_CQDJNptlxOVIRgT4DxHnAKT9KohxfNhSH9bC", + }, + .datetimez = .{ + .url = "git+https://github.com/frmdstryr/zig-datetime.git#3a39a21e6e34dcb0ade0ff828d0914d40ba535f3", + .hash = "datetime-0.8.0-cJNXzP_YAQBxQ5hkNNP6ScnG5XsqciJmeP5RVV4xwCBA", + }, + }, +} diff --git a/frameworks/Zig/dusty/dusty.dockerfile b/frameworks/Zig/dusty/dusty.dockerfile new file mode 100644 index 00000000000..a0b960494ec --- /dev/null +++ b/frameworks/Zig/dusty/dusty.dockerfile @@ -0,0 +1,38 @@ +FROM debian:12.9 AS build + +WORKDIR /app + +COPY src src +COPY build.zig.zon build.zig.zon +COPY build.zig build.zig + +ARG ZIG_VER=0.15.2 + +RUN apt-get update && apt-get install -y wget xz-utils ca-certificates git + +RUN wget https://ziglang.org/download/${ZIG_VER}/zig-$(uname -m)-linux-${ZIG_VER}.tar.xz + +RUN tar -xvf zig-$(uname -m)-linux-${ZIG_VER}.tar.xz + +RUN mv zig-$(uname -m)-linux-${ZIG_VER} /usr/local/zig + +ENV PATH="/usr/local/zig:$PATH" +RUN zig build -Doptimize=ReleaseFast + + +FROM debian:12-slim + +ENV PG_USER=benchmarkdbuser +ENV PG_PASS=benchmarkdbpass +ENV PG_DB=hello_world +ENV PG_HOST=tfb-database +ENV PG_PORT=5432 + +RUN apt-get -qq update +RUN apt-get -qy install ca-certificates + +COPY --from=build /app/zig-out/bin/dusty /server + +EXPOSE 3000 + +ENTRYPOINT ["/server"] diff --git a/frameworks/Zig/dusty/src/endpoints.zig b/frameworks/Zig/dusty/src/endpoints.zig new file mode 100644 index 00000000000..9c173d4ff11 --- /dev/null +++ b/frameworks/Zig/dusty/src/endpoints.zig @@ -0,0 +1,136 @@ +const std = @import("std"); +const dusty = @import("dusty"); +const pg = @import("pg"); +const datetimez = @import("datetimez"); + +pub var date_str: [29]u8 = undefined; + +pub const Global = struct { + pool: *pg.Pool, + rand: *std.Random, +}; + +const World = struct { + id: i32, + randomNumber: i32, +}; + +const Fortune = struct { + id: i32, + message: []const u8, +}; + +pub fn plaintext(_: *Global, _: *dusty.Request, res: *dusty.Response) !void { + try setHeaders(res); + + try res.header("Content-Type", "text/plain"); + res.body = "Hello, World!"; +} + +pub fn json(_: *Global, _: *dusty.Request, res: *dusty.Response) !void { + try setHeaders(res); + + try res.json(.{ .message = "Hello, World!" }, .{}); +} + +pub fn db(global: *Global, _: *dusty.Request, res: *dusty.Response) !void { + try setHeaders(res); + + const random_number = 1 + (global.rand.uintAtMostBiased(u32, 9999)); + + const world = getWorld(global.pool, random_number) catch |err| { + std.debug.print("Error querying database: {}\n", .{err}); + return; + }; + + try res.json(world, .{}); +} + +pub fn fortune(global: *Global, _: *dusty.Request, res: *dusty.Response) !void { + try setHeaders(res); + + const fortunes_html = try getFortunesHtml(res.arena, global.pool); + + try res.header("Content-Type", "text/html; charset=utf-8"); + res.body = fortunes_html; +} + +fn getWorld(pool: *pg.Pool, random_number: u32) !World { + var conn = try pool.acquire(); + defer conn.release(); + + const row_result = try conn.row("SELECT id, randomNumber FROM World WHERE id = $1", .{random_number}); + + var row = row_result.?; + defer row.deinit() catch {}; + + return World{ .id = row.get(i32, 0), .randomNumber = row.get(i32, 1) }; +} + +fn setHeaders(res: *dusty.Response) !void { + try res.header("Server", "Dusty"); + try res.header("Date", try res.arena.dupe(u8, &date_str)); +} + +fn getFortunesHtml(allocator: std.mem.Allocator, pool: *pg.Pool) ![]const u8 { + const fortunes = try getFortunes(allocator, pool); + + var sb = try std.ArrayListUnmanaged(u8).initCapacity(allocator, 0); + + const writer = sb.writer(allocator); + try sb.appendSlice(allocator, "Fortunes
idmessage
"); Render::render_escaped(&item.id, &mut buf)?; buf.push_str(""); - Render::render_escaped(&item.message, &mut buf)?; + Render::render_escaped(item.message.as_str(), &mut buf)?; buf.push_str("
"); + + for (fortunes) |ft| { + try writer.print("", .{ + ft.id, + try escape_html(allocator, ft.message), + }); + } + + try sb.appendSlice(allocator, "
idmessage
{d}{s}
"); + + return sb.toOwnedSlice(allocator); +} + +fn getFortunes(allocator: std.mem.Allocator, pool: *pg.Pool) ![]const Fortune { + var conn = try pool.acquire(); + defer conn.release(); + + var rows = try conn.query("SELECT id, message FROM Fortune", .{}); + defer rows.deinit(); + + var fortunes = try std.ArrayListUnmanaged(Fortune).initCapacity(allocator, 0); + defer fortunes.deinit(allocator); + + while (try rows.next()) |row| { + const current_fortune = Fortune{ .id = row.get(i32, 0), .message = row.get([]const u8, 1) }; + try fortunes.append(allocator, current_fortune); + } + + const zero_fortune = Fortune{ .id = 0, .message = "Additional fortune added at request time." }; + try fortunes.append(allocator, zero_fortune); + + const fortunes_slice = try fortunes.toOwnedSlice(allocator); + std.mem.sort(Fortune, fortunes_slice, {}, cmpFortuneByMessage); + + return fortunes_slice; +} + +fn cmpFortuneByMessage(_: void, a: Fortune, b: Fortune) bool { + return std.mem.order(u8, a.message, b.message).compare(std.math.CompareOperator.lt); +} + +fn escape_html(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { + var output = try std.ArrayListUnmanaged(u8).initCapacity(allocator, 0); + defer output.deinit(allocator); + + for (input) |char| { + switch (char) { + '<' => try output.appendSlice(allocator, "<"), + '>' => try output.appendSlice(allocator, ">"), + else => try output.append(allocator, char), + } + } + + return output.toOwnedSlice(allocator); +} diff --git a/frameworks/Zig/dusty/src/main.zig b/frameworks/Zig/dusty/src/main.zig new file mode 100644 index 00000000000..780db1a19b1 --- /dev/null +++ b/frameworks/Zig/dusty/src/main.zig @@ -0,0 +1,98 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const dusty = @import("dusty"); +const zio = @import("zio"); +const pg = @import("pg"); +const datetimez = @import("datetimez"); +const pool = @import("pool.zig"); + +const endpoints = @import("endpoints.zig"); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{ + .thread_safe = true, + }){}; + defer { + if (builtin.mode == .Debug) _ = gpa.deinit(); + } + + const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.smp_allocator; + + var io = try zio.Runtime.init(allocator, .{}); + defer io.deinit(); + + var task = try zio.spawn(runServer, .{ allocator, io }); + try task.join(); +} + +fn runServer(allocator: std.mem.Allocator, io: *zio.Runtime) !void { + _ = io; + + var pg_pool = try pool.initPool(allocator); + defer pg_pool.deinit(); + + const date_thread = try std.Thread.spawn(.{}, struct { + fn update() !void { + while (true) { + const now = datetimez.datetime.Date.now(); + const time = datetimez.datetime.Time.now(); + + const TB_DATE_FMT = "{s:0>3}, {d:0>2} {s:0>3} {d:0>4} {d:0>2}:{d:0>2}:{d:0>2} GMT"; + _ = try std.fmt.bufPrint(&endpoints.date_str, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); + std.Thread.sleep(std.time.ns_per_ms * 980); + } + } + }.update, .{}); + + date_thread.detach(); + + var prng: std.Random.DefaultPrng = .init(@as(u64, @bitCast(std.time.milliTimestamp()))); + + var rand = prng.random(); + + var global = endpoints.Global{ + .pool = pg_pool, + .rand = &rand, + }; + + const port: u16 = 3000; + + const DustyServer = dusty.Server(endpoints.Global); + + const config: dusty.ServerConfig = .{ + .timeout = .{ + .request = 60 * std.time.ms_per_s, + .keepalive = 300 * std.time.ms_per_s, + } + }; + + var server = DustyServer.init(allocator, config, &global); + defer server.deinit(); + + server.router.get("/json", endpoints.json); + server.router.get("/plaintext", endpoints.plaintext); + server.router.get("/db", endpoints.db); + server.router.get("/fortunes", endpoints.fortune); + + std.debug.print("Dusty listening at 0.0.0.0:{d}\n", .{port}); + + const addr = try zio.net.IpAddress.parseIp("0.0.0.0", port); + + var listen_task = try zio.spawn(DustyServer.listen, .{ &server, addr }); + defer listen_task.cancel(); + + var sigint = try zio.Signal.init(.interrupt); + defer sigint.deinit(); + + var sigterm = try zio.Signal.init(.terminate); + defer sigterm.deinit(); + + const result = try zio.select(.{ .task = &listen_task, .sigint = &sigint, .sigterm = &sigterm }); + switch (result) { + .task => |r| return r, + .sigint, .sigterm => { + listen_task.cancel(); + return; + }, + } +} diff --git a/frameworks/Zig/dusty/src/pool.zig b/frameworks/Zig/dusty/src/pool.zig new file mode 100644 index 00000000000..b8944b547db --- /dev/null +++ b/frameworks/Zig/dusty/src/pool.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const pg = @import("pg"); + +const Allocator = std.mem.Allocator; +const Pool = pg.Pool; + +pub fn initPool(allocator: Allocator) !*pg.Pool { + const info = try parsePostgresConnStr(allocator); + + const pg_pool = try Pool.init(allocator, .{ + .size = 56, + .connect = .{ + .port = info.port, + .host = info.hostname, + }, + .auth = .{ + .username = info.username, + .database = info.database, + .password = info.password, + }, + .timeout = 10_000, + }); + + return pg_pool; +} + +pub const ConnectionInfo = struct { + username: []const u8, + password: []const u8, + hostname: []const u8, + port: u16, + database: []const u8, +}; + +fn addressAsString(address: std.net.Address) ![]const u8 { + const bytes = @as(*const [4]u8, @ptrCast(&address.in.sa.addr)); + + var buffer: [256]u8 = undefined; + var source = std.io.StreamSource{ .buffer = std.io.fixedBufferStream(&buffer) }; + var writer = source.writer(); + + //try writer.writeAll("Hello, World!"); + + try writer.print("{}.{}.{}.{}", .{ + bytes[0], + bytes[1], + bytes[2], + bytes[3], + }); + + const output = source.buffer.getWritten(); + + return output; +} + +fn parsePostgresConnStr(allocator: Allocator) !ConnectionInfo { + const pg_port = try getEnvVar(allocator, "PG_PORT", "5432"); + // std.debug.print("tfb port {s}\n", .{pg_port}); + var port = try std.fmt.parseInt(u16, pg_port, 0); + + if (port == 0) { + port = 5432; + } + + return ConnectionInfo{ + .username = try getEnvVar(allocator, "PG_USER", "benchmarkdbuser"), + .password = try getEnvVar(allocator, "PG_PASS", "benchmarkdbpass"), + .hostname = try getEnvVar(allocator, "PG_HOST", "localhost"), + .port = port, + .database = try getEnvVar(allocator, "PG_DB", "hello_world"), + }; +} + +fn getEnvVar(allocator: Allocator, name: []const u8, default: []const u8) ![]const u8 { + const env_var = std.process.getEnvVarOwned(allocator, name) catch |err| switch (err) { + error.EnvironmentVariableNotFound => return default, + error.OutOfMemory => return err, + error.InvalidWtf8 => return err, + }; + + if (env_var.len == 0) return default; + + return env_var; +} diff --git a/frameworks/Zig/oxelot-http/benchmark_config.json b/frameworks/Zig/oxelot-http/benchmark_config.json new file mode 100644 index 00000000000..4dff8b1fe03 --- /dev/null +++ b/frameworks/Zig/oxelot-http/benchmark_config.json @@ -0,0 +1,52 @@ +{ + "framework": "oxelot-http", + "tests": [{ + "default": { + "dockerfile": "oxelot-http.dockerfile", + "docker_cmd": "/app/techempower", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8000, + "approach": "Realistic", + "classification": "Platform", + "database": "none", + "framework": "oxelot-http", + "language": "Zig", + "flavor": "None", + "orm": "Raw", + "platform": "Zig", + "webserver": "Custom", + "os": "Linux", + "database_os": "Linux", + "display_name": "oxelot-http", + "notes": "", + "versus": "None" + }, + "postgres": { + "dockerfile": "oxelot-http.dockerfile", + "docker_cmd": "/app/techempower", + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "oxelot-http", + "language": "Zig", + "flavor": "None", + "orm": "Raw", + "platform": "Zig", + "webserver": "Custom", + "os": "Linux", + "database_os": "Linux", + "display_name": "oxelot-http [PostgreSQL]", + "notes": "", + "versus": "None" + } + }] +} diff --git a/frameworks/Zig/oxelot-http/build.zig b/frameworks/Zig/oxelot-http/build.zig new file mode 100644 index 00000000000..f7a50b1420b --- /dev/null +++ b/frameworks/Zig/oxelot-http/build.zig @@ -0,0 +1,38 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const oxelot_dep = b.dependency("oxelot_http", .{ + .target = target, + .optimize = optimize, + }); + + const exe = b.addExecutable(.{ + .name = "techempower", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = .ReleaseFast, + }), + }); + + exe.root_module.addImport("http", oxelot_dep.module("http")); + exe.root_module.addImport("pg", oxelot_dep.module("pg")); + + // picohttpparser C source (needed by http module) + exe.root_module.addIncludePath(oxelot_dep.path("lib/picohttpparser")); + exe.root_module.addCSourceFile(.{ + .file = oxelot_dep.path("lib/picohttpparser/picohttpparser.c"), + .flags = &.{"-O3"}, + }); + + exe.root_module.link_libc = true; + exe.root_module.linkSystemLibrary("pq", .{}); + + b.installArtifact(exe); + + const run_step = b.step("run", "Run the TechEmpower benchmark server"); + run_step.dependOn(&b.addRunArtifact(exe).step); +} diff --git a/frameworks/Zig/oxelot-http/build.zig.zon b/frameworks/Zig/oxelot-http/build.zig.zon new file mode 100644 index 00000000000..c423ee7196c --- /dev/null +++ b/frameworks/Zig/oxelot-http/build.zig.zon @@ -0,0 +1,19 @@ +.{ + .fingerprint = 0x41aa17ef09162160, + .name = .oxelot_techempower, + .version = "0.1.0", + .minimum_zig_version = "0.16.0", + + .dependencies = .{ + .oxelot_http = .{ + .url = "git+https://github.com/samcschneider/oxelot-http.git#d745cad1acd0a6a5d46558577d52e0e61ccb97df", + .hash = "oxelot_http-0.1.0-7mzzN6bKDwA7EICPqRQcwwkqwa7oD0hPB_d8qNfXA_VC", + }, + }, + + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/frameworks/Zig/oxelot-http/oxelot-http.dockerfile b/frameworks/Zig/oxelot-http/oxelot-http.dockerfile new file mode 100644 index 00000000000..4c7af7b89ed --- /dev/null +++ b/frameworks/Zig/oxelot-http/oxelot-http.dockerfile @@ -0,0 +1,49 @@ +FROM debian:bookworm-slim AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + xz-utils \ + git \ + libpq-dev \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* + +# Install Zig (pinned dev build hosted on oxelot-http releases) +ARG ZIG_VERSION=0.16.0-dev.1859+212968c57 +RUN curl -sSL "https://github.com/samcschneider/oxelot-http/releases/download/v0.1.0/zig-x86_64-linux-${ZIG_VERSION}.tar.xz" \ + -o /tmp/zig.tar.xz && \ + tar -xJf /tmp/zig.tar.xz -C /usr/local && \ + ln -s /usr/local/zig-x86_64-linux-${ZIG_VERSION}/zig /usr/local/bin/zig && \ + rm /tmp/zig.tar.xz + +WORKDIR /build + +# Copy source files +COPY build.zig build.zig.zon ./ +COPY src/ src/ + +# Build (fetches oxelot-http dependency from GitHub) +RUN zig build -Doptimize=ReleaseFast + +# --- Runtime stage --- +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libpq5 \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /build/zig-out/bin/techempower /app/techempower + +ENV DBHOST=tfb-database +ENV DBPORT=5432 +ENV DBNAME=hello_world +ENV DBUSER=benchmarkdbuser +ENV DBPASS=benchmarkdbpass +ENV DB_CONNS=4 +ENV PORT=8000 + +EXPOSE 8000 + +CMD ["/app/techempower"] diff --git a/frameworks/Zig/oxelot-http/src/main.zig b/frameworks/Zig/oxelot-http/src/main.zig new file mode 100644 index 00000000000..f29875cfa18 --- /dev/null +++ b/frameworks/Zig/oxelot-http/src/main.zig @@ -0,0 +1,889 @@ +// TechEmpower Framework Benchmarks — oxelot-http entry +// +// Implements all 7 TFB test types: +// 1. /json — JSON serialization +// 2. /plaintext — Plaintext response +// 3. /db — Single database query +// 4. /queries?q=N — Multiple database queries (pipelined) +// 5. /fortunes — Server-side HTML template with DB data +// 6. /updates?q=N — Multiple updates (batched CASE/WHEN) +// 7. /cached-queries?q=N — In-memory cached world rows +// +// DB handlers use async libpq with io_uring poll for non-blocking DB I/O. +// +// Run with: zig build techempower +// Test with: wrk -t8 -c256 -d15s http://localhost:8080/json + +const std = @import("std"); +const http = @import("http"); +const pg = @import("pg"); + +// ============================================================================ +// Types +// ============================================================================ + +const World = struct { + id: i32, + randomnumber: i32, +}; + +const Fortune = struct { + id: i32, + message: []const u8, +}; + +// ============================================================================ +// Helpers +// ============================================================================ + +fn writeInt(buf: []u8, val: usize) usize { + if (val < 10) { + buf[0] = '0' + @as(u8, @intCast(val)); + return 1; + } else if (val < 100) { + buf[0] = '0' + @as(u8, @intCast(val / 10)); + buf[1] = '0' + @as(u8, @intCast(val % 10)); + return 2; + } else if (val < 1000) { + buf[0] = '0' + @as(u8, @intCast(val / 100)); + buf[1] = '0' + @as(u8, @intCast(val / 10 % 10)); + buf[2] = '0' + @as(u8, @intCast(val % 10)); + return 3; + } else if (val < 10000) { + buf[0] = '0' + @as(u8, @intCast(val / 1000)); + buf[1] = '0' + @as(u8, @intCast(val / 100 % 10)); + buf[2] = '0' + @as(u8, @intCast(val / 10 % 10)); + buf[3] = '0' + @as(u8, @intCast(val % 10)); + return 4; + } else { + buf[0] = '0' + @as(u8, @intCast(val / 10000)); + buf[1] = '0' + @as(u8, @intCast(val / 1000 % 10)); + buf[2] = '0' + @as(u8, @intCast(val / 100 % 10)); + buf[3] = '0' + @as(u8, @intCast(val / 10 % 10)); + buf[4] = '0' + @as(u8, @intCast(val % 10)); + return 5; + } +} + +// ============================================================================ +// Thread-local state +// ============================================================================ + +threadlocal var tl_rng: std.Random.Xoshiro256 = undefined; +threadlocal var tl_rng_init: bool = false; + +fn getRng() *std.Random.Xoshiro256 { + if (!tl_rng_init) { + var seed: u64 = 0; + if (std.posix.clock_gettime(.REALTIME)) |ts| { + seed = @bitCast(@as(i64, ts.sec) *% 1_000_000_000 +% @as(i64, ts.nsec)); + } else |_| {} + tl_rng = std.Random.Xoshiro256.init(seed); + tl_rng_init = true; + } + return &tl_rng; +} + +fn randomWorldId() i32 { + return @as(i32, @intCast(getRng().random().intRangeAtMost(u32, 1, 10000))); +} + +/// Get a null-terminated env var value. Returns null if not set. +fn envZ(name: [*:0]const u8) ?[:0]const u8 { + const val = std.c.getenv(name) orelse return null; + return std.mem.span(val); +} + +fn getDbConnString() [:0]const u8 { + // Build connection string — stored in global so it persists + const S = struct { + var buf: [512]u8 = undefined; + var str: ?[:0]const u8 = null; + }; + if (S.str) |s| return s; + + const host = envZ("DBHOST") orelse "tfb-database"; + const port_str = std.posix.getenv("DBPORT") orelse "5432"; + const database = envZ("DBNAME") orelse "hello_world"; + const username = envZ("DBUSER") orelse "benchmarkdbuser"; + const password = envZ("DBPASS") orelse "benchmarkdbpass"; + + const result = std.fmt.bufPrintZ(&S.buf, "host={s} port={s} dbname={s} user={s} password={s}", .{ + host, port_str, database, username, password, + }) catch "host=tfb-database port=5432 dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass"; + S.str = result; + return result; +} + +// Prepared statements shared across all connections +const prepared_stmts = [_]pg.PreparedStmt{ + .{ .name = "world", .sql = "SELECT id, randomnumber FROM world WHERE id=$1", .n_params = 1 }, + .{ .name = "fortune", .sql = "SELECT id, message FROM fortune", .n_params = 0 }, + .{ + .name = "update_worlds", + .sql = "UPDATE world SET randomnumber = new.rnum FROM " ++ + "(SELECT * FROM UNNEST($1::int[], $2::int[]) AS v(id, rnum) ORDER BY 1) AS new " ++ + "WHERE world.id = new.id", + .n_params = 2, + }, +}; + +// ============================================================================ +// Async poll callbacks (called from server's io_uring event loop) +// ============================================================================ + +fn asyncPollInit(ring: *http.IoUring) ?*anyopaque { + const num_conns: u8 = if (std.posix.getenv("DB_CONNS")) |env| + std.fmt.parseInt(u8, env, 10) catch 4 + else + 4; + const pool = pg.DbConnPool.init(std.heap.c_allocator, .{ + .conn_string = getDbConnString(), + .num_conns = num_conns, + .prepared_statements = &prepared_stmts, + }) catch |err| { + std.log.err("Failed to init async DB pool: {}", .{err}); + return null; + }; + _ = ring; // ring is used later via getAsyncPollRing() + + // Store on heap so we can return a stable pointer + const heap_pool = std.heap.c_allocator.create(pg.DbConnPool) catch return null; + heap_pool.* = pool; + return @ptrCast(heap_pool); +} + +fn asyncPollDeinit(state: *anyopaque) void { + const pool: *pg.DbConnPool = @ptrCast(@alignCast(state)); + pool.deinit(); + std.heap.c_allocator.destroy(pool); +} + +fn asyncPollHandler(state: *anyopaque, ring: *http.IoUring, db_conn_idx: u8, writer: *http.AsyncPollResponseWriter) void { + const pool: *pg.DbConnPool = @ptrCast(@alignCast(state)); + // Use ResponseList that matches the pg.ResponseList interface + var responses = pg.ResponseList.init(); + pool.handlePoll(ring, db_conn_idx, &responses); + + // Transfer to the server's writer + for (responses.items[0..responses.count]) |item| { + writer.add(item.conn_ptr, item.data); + } +} + +// ============================================================================ +// Cached queries — global cache refreshed by background thread +// ============================================================================ + +const CachedWorld = struct { + id: i32, + randomnumber: std.atomic.Value(i32), +}; + +var cached_worlds: [10001]CachedWorld = undefined; +var cache_ready = std.atomic.Value(bool).init(false); + +fn startCacheRefreshThread() !void { + _ = try std.Thread.spawn(.{}, cacheRefreshLoop, .{}); +} + +fn cacheRefreshLoop() void { + while (true) { + refreshCache() catch |err| { + std.log.err("Cache refresh failed: {}", .{err}); + }; + std.posix.nanosleep(5, 0); + } +} + +fn refreshCache() !void { + const db_config: pg.ConnConfig = .{ + .host = envZ("DBHOST") orelse "tfb-database", + .port = if (std.fmt.parseInt(u16, std.posix.getenv("DBPORT") orelse "5432", 10)) |p| p else |_| 5432, + .database = envZ("DBNAME") orelse "hello_world", + .username = envZ("DBUSER") orelse "benchmarkdbuser", + .password = envZ("DBPASS") orelse "benchmarkdbpass", + }; + var conn = try pg.Connection.connect(db_config); + defer conn.deinit(); + + var result = try conn.query("SELECT id, randomnumber FROM world"); + defer result.deinit(); + + const rows = result.rowCount(); + for (0..rows) |i| { + const id = result.getInt(i, 0) orelse continue; + const rn = result.getInt(i, 1) orelse continue; + if (id >= 1 and id <= 10000) { + const idx: usize = @intCast(id); + cached_worlds[idx].id = id; + cached_worlds[idx].randomnumber.store(rn, .release); + } + } + + cache_ready.store(true, .release); +} + +// ============================================================================ +// Raw response helpers — bypass Response serialization for near-zero allocs +// ============================================================================ + +threadlocal var tl_response_buf: [65536]u8 = undefined; + +fn writeRawResponse( + content_type: []const u8, + body: []const u8, + date: []const u8, +) []const u8 { + var buf = &tl_response_buf; + var pos: usize = 0; + + appendSlice(buf, &pos, "HTTP/1.1 200 OK\r\nServer: oxelot-http\r\nContent-Type: "); + appendSlice(buf, &pos, content_type); + appendSlice(buf, &pos, "\r\nContent-Length: "); + pos += writeIntBuf(buf[pos..], body.len); + appendSlice(buf, &pos, "\r\nDate: "); + appendSlice(buf, &pos, date); + appendSlice(buf, &pos, "\r\n\r\n"); + appendSlice(buf, &pos, body); + + return buf[0..pos]; +} + +/// Build a raw HTTP response and allocate a heap copy (for async callbacks) +fn writeRawResponseAlloc( + content_type: []const u8, + body: []const u8, + date: []const u8, +) ?[]u8 { + const raw = writeRawResponse(content_type, body, date); + const buf = std.heap.c_allocator.alloc(u8, raw.len) catch return null; + @memcpy(buf, raw); + return buf; +} + +fn appendSlice(buf: []u8, pos: *usize, data: []const u8) void { + @memcpy(buf[pos.*..][0..data.len], data); + pos.* += data.len; +} + +fn writeIntBuf(buf: []u8, val: usize) usize { + if (val == 0) { + buf[0] = '0'; + return 1; + } + var tmp: [20]u8 = undefined; + var n: usize = 0; + var v = val; + while (v > 0) { + tmp[n] = '0' + @as(u8, @intCast(v % 10)); + v /= 10; + n += 1; + } + for (0..n) |i| { + buf[i] = tmp[n - 1 - i]; + } + return n; +} + +fn getDate() []const u8 { + return http.getHttpDate(); +} + +/// Get cached HTTP date from server's threadlocal (used in async callbacks +/// where we don't have a Context). +fn getCachedDate() []const u8 { + // The server caches the date in its own threadlocal; we can use it here + // since callbacks run on the same io_uring thread. + // For simplicity, just format a fresh one. + const S = struct { + threadlocal var date_buf: [29]u8 = undefined; + threadlocal var cached_ts: i64 = 0; + }; + const ts = std.posix.clock_gettime(.REALTIME) catch return "Thu, 01 Jan 1970 00:00:00 GMT"; + if (ts.sec != S.cached_ts) { + formatHttpDate(&S.date_buf, ts.sec); + S.cached_ts = ts.sec; + } + return &S.date_buf; +} + +const day_names = [_][]const u8{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +const month_names = [_][]const u8{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +fn formatHttpDate(buf: []u8, timestamp: i64) void { + const epoch_secs: std.time.epoch.EpochSeconds = .{ .secs = @intCast(timestamp) }; + const day_secs = epoch_secs.getDaySeconds(); + const epoch_day = epoch_secs.getEpochDay(); + const year_day = epoch_day.calculateYearDay(); + const month_day = year_day.calculateMonthDay(); + + const wday_idx: usize = @intCast(@mod(epoch_day.day + 4, 7)); + @memcpy(buf[0..3], day_names[wday_idx]); + buf[3] = ','; + buf[4] = ' '; + const day_num = month_day.day_index + 1; + buf[5] = '0' + @as(u8, @intCast(day_num / 10)); + buf[6] = '0' + @as(u8, @intCast(day_num % 10)); + buf[7] = ' '; + @memcpy(buf[8..11], month_names[@intFromEnum(month_day.month) - 1]); + buf[11] = ' '; + const year = year_day.year; + buf[12] = '0' + @as(u8, @intCast(@divFloor(year, 1000))); + buf[13] = '0' + @as(u8, @intCast(@mod(@divFloor(year, 100), 10))); + buf[14] = '0' + @as(u8, @intCast(@mod(@divFloor(year, 10), 10))); + buf[15] = '0' + @as(u8, @intCast(@mod(year, 10))); + buf[16] = ' '; + const hours = day_secs.getHoursIntoDay(); + const mins = day_secs.getMinutesIntoHour(); + const secs = day_secs.getSecondsIntoMinute(); + buf[17] = '0' + @as(u8, @intCast(hours / 10)); + buf[18] = '0' + @as(u8, @intCast(hours % 10)); + buf[19] = ':'; + buf[20] = '0' + @as(u8, @intCast(mins / 10)); + buf[21] = '0' + @as(u8, @intCast(mins % 10)); + buf[22] = ':'; + buf[23] = '0' + @as(u8, @intCast(secs / 10)); + buf[24] = '0' + @as(u8, @intCast(secs % 10)); + buf[25] = ' '; + buf[26] = 'G'; + buf[27] = 'M'; + buf[28] = 'T'; +} + +// ============================================================================ +// Handlers — sync (non-DB) +// ============================================================================ + +fn handleJson(ctx: *http.Context) !void { + var buf: [64]u8 = undefined; + const body = http.stringify(&buf, .{ .message = "Hello, World!" }) catch unreachable; + ctx.response.setRaw(writeRawResponse("application/json", body, getDate())); +} + +fn handlePlaintext(ctx: *http.Context) !void { + ctx.response.setRaw(writeRawResponse("text/plain; charset=utf-8", "Hello, World!", getDate())); +} + +fn handleCachedQueries(ctx: *http.Context) !void { + if (!cache_ready.load(.acquire)) { + _ = ctx.response.internalServerError(); + return; + } + + const count = parseQueryCount(ctx, "q"); + var worlds: [500]World = undefined; + + for (0..count) |i| { + const id = randomWorldId(); + const idx: usize = @intCast(id); + worlds[i] = .{ + .id = cached_worlds[idx].id, + .randomnumber = cached_worlds[idx].randomnumber.load(.acquire), + }; + } + + sendWorldsRaw(ctx, worlds[0..count]); +} + +// ============================================================================ +// Handlers — async DB +// ============================================================================ + +fn handleDb(ctx: *http.Context) !void { + const pool = getPool() orelse { + _ = ctx.response.internalServerError(); + return; + }; + const ring = http.getAsyncPollRing() orelse { + _ = ctx.response.internalServerError(); + return; + }; + + const id = randomWorldId(); + + // Format the id parameter (must be alive until submit returns) + var id_buf: [16]u8 = undefined; + const id_str = std.fmt.bufPrintZ(&id_buf, "{d}", .{id}) catch unreachable; + + var params: [8]?[*:0]const u8 = .{null} ** 8; + params[0] = id_str.ptr; + + const req = pg.DbRequest{ + .http_conn_ptr = http.getCurrentConnPtr(), + .operation = .{ .single_query = .{ + .stmt_name = "world", + .params = params, + .n_params = 1, + } }, + .callback = dbCallback, + .result_data = .{ + .worlds = undefined, + .world_count = 0, + .fortunes = undefined, + .fortune_count = 0, + .err = false, + }, + .phase = .initial, + .pipeline_results_remaining = 0, + .pipeline_results_consumed = 0, + .active = false, + }; + + if (!pool.submit(ring, req)) { + _ = ctx.response.internalServerError(); + return; + } + + ctx.response.async_pending = true; +} + +fn handleQueries(ctx: *http.Context) !void { + const pool = getPool() orelse { + _ = ctx.response.internalServerError(); + return; + }; + const ring = http.getAsyncPollRing() orelse { + _ = ctx.response.internalServerError(); + return; + }; + + const count = parseQueryCount(ctx, "q"); + + // Fill param buffers with random ids + var param_bufs: [500][16]u8 = undefined; + for (0..count) |i| { + _ = std.fmt.bufPrintZ(¶m_bufs[i], "{d}", .{randomWorldId()}) catch unreachable; + } + + const req = pg.DbRequest{ + .http_conn_ptr = http.getCurrentConnPtr(), + .operation = .{ .pipeline_query = .{ + .stmt_name = "world", + .param_bufs = param_bufs, + .count = @intCast(count), + } }, + .callback = queriesCallback, + .result_data = .{ + .worlds = undefined, + .world_count = 0, + .fortunes = undefined, + .fortune_count = 0, + .err = false, + }, + .phase = .initial, + .pipeline_results_remaining = 0, + .pipeline_results_consumed = 0, + .active = false, + }; + + if (!pool.submit(ring, req)) { + _ = ctx.response.internalServerError(); + return; + } + + ctx.response.async_pending = true; +} + +fn handleFortunes(ctx: *http.Context) !void { + const pool = getPool() orelse { + _ = ctx.response.internalServerError(); + return; + }; + const ring = http.getAsyncPollRing() orelse { + _ = ctx.response.internalServerError(); + return; + }; + + const req = pg.DbRequest{ + .http_conn_ptr = http.getCurrentConnPtr(), + .operation = .{ .fortune_query = .{ + .stmt_name = "fortune", + } }, + .callback = fortuneCallback, + .result_data = .{ + .worlds = undefined, + .world_count = 0, + .fortunes = undefined, + .fortune_count = 0, + .err = false, + }, + .phase = .initial, + .pipeline_results_remaining = 0, + .pipeline_results_consumed = 0, + .active = false, + }; + + if (!pool.submit(ring, req)) { + _ = ctx.response.internalServerError(); + return; + } + + ctx.response.async_pending = true; +} + +fn handleUpdates(ctx: *http.Context) !void { + const pool = getPool() orelse { + _ = ctx.response.internalServerError(); + return; + }; + const ring = http.getAsyncPollRing() orelse { + _ = ctx.response.internalServerError(); + return; + }; + + const count = parseQueryCount(ctx, "q"); + + // Fill param buffers with random ids + var param_bufs: [500][16]u8 = undefined; + for (0..count) |i| { + _ = std.fmt.bufPrintZ(¶m_bufs[i], "{d}", .{randomWorldId()}) catch unreachable; + } + + const req = pg.DbRequest{ + .http_conn_ptr = http.getCurrentConnPtr(), + .operation = .{ .pipeline_query = .{ + .stmt_name = "world", + .param_bufs = param_bufs, + .count = @intCast(count), + } }, + .callback = updatesReadCallback, + .result_data = .{ + .worlds = undefined, + .world_count = 0, + .fortunes = undefined, + .fortune_count = 0, + .err = false, + }, + .phase = .initial, + .pipeline_results_remaining = 0, + .pipeline_results_consumed = 0, + .active = false, + }; + + if (!pool.submit(ring, req)) { + _ = ctx.response.internalServerError(); + return; + } + + ctx.response.async_pending = true; +} + +// ============================================================================ +// DB Callbacks (invoked from io_uring poll handler when results are ready) +// ============================================================================ + +fn dbCallback(conn_ptr: usize, result: *pg.DbResult, phase: pg.async_pool.Phase, pool: *pg.DbConnPool) ?[]const u8 { + _ = conn_ptr; + _ = phase; + _ = pool; + + if (result.err or result.world_count == 0) { + return writeRawResponseAlloc("application/json", "{\"error\":\"db\"}", getCachedDate()); + } + + const w = result.worlds[0]; + var body_buf: [64]u8 = undefined; + var writer = http.JsonWriter.init(&body_buf); + writer.writeRaw("{\"id\":") catch unreachable; + writer.writeInt(w.id) catch unreachable; + writer.writeRaw(",\"randomnumber\":") catch unreachable; + writer.writeInt(w.randomnumber) catch unreachable; + writer.writeByte('}') catch unreachable; + + return writeRawResponseAlloc("application/json", writer.getWritten(), getCachedDate()); +} + +fn queriesCallback(conn_ptr: usize, result: *pg.DbResult, phase: pg.async_pool.Phase, pool: *pg.DbConnPool) ?[]const u8 { + _ = conn_ptr; + _ = phase; + _ = pool; + + if (result.err) { + return writeRawResponseAlloc("application/json", "[]", getCachedDate()); + } + + const worlds = worldsFromResult(result); + const body = writeWorldsJsonRaw(worlds); + return writeRawResponseAlloc("application/json", body, getCachedDate()); +} + +fn fortuneCallback(conn_ptr: usize, result: *pg.DbResult, phase: pg.async_pool.Phase, pool: *pg.DbConnPool) ?[]const u8 { + _ = conn_ptr; + _ = phase; + _ = pool; + + if (result.err) { + return writeRawResponseAlloc("text/html; charset=utf-8", "error", getCachedDate()); + } + + // Build Fortune slice from result data + var fortunes: [128]Fortune = undefined; + var fortune_count: usize = 0; + + for (0..result.fortune_count) |i| { + const fr = &result.fortunes[i]; + fortunes[fortune_count] = .{ + .id = fr.id, + .message = fr.message[0..fr.message_len], + }; + fortune_count += 1; + } + + // Add the additional fortune + fortunes[fortune_count] = .{ + .id = 0, + .message = "Additional fortune added at request time.", + }; + fortune_count += 1; + + // Sort by message + std.mem.sort(Fortune, fortunes[0..fortune_count], {}, struct { + fn lessThan(_: void, a: Fortune, b: Fortune) bool { + return std.mem.order(u8, a.message, b.message) == .lt; + } + }.lessThan); + + // Render HTML + var buf: [32768]u8 = undefined; + var pos: usize = 0; + + const header_html = "Fortunes"; + @memcpy(buf[pos..][0..header_html.len], header_html); + pos += header_html.len; + + for (fortunes[0..fortune_count]) |f| { + const row_start = ""; + @memcpy(buf[pos..][0..row_end.len], row_end); + pos += row_end.len; + } + + const footer_html = "
idmessage
"; + @memcpy(buf[pos..][0..row_start.len], row_start); + pos += row_start.len; + + const id_slice = std.fmt.bufPrint(buf[pos..], "{d}", .{f.id}) catch ""; + pos += id_slice.len; + + const mid_html = ""; + @memcpy(buf[pos..][0..mid_html.len], mid_html); + pos += mid_html.len; + + pos += htmlEscape(buf[pos..], f.message); + + const row_end = "
"; + @memcpy(buf[pos..][0..footer_html.len], footer_html); + pos += footer_html.len; + + return writeRawResponseAlloc("text/html; charset=utf-8", buf[0..pos], getCachedDate()); +} + +fn updatesReadCallback(conn_ptr: usize, result: *pg.DbResult, phase: pg.async_pool.Phase, pool: *pg.DbConnPool) ?[]const u8 { + _ = phase; + + if (result.err) { + return writeRawResponseAlloc("application/json", "[]", getCachedDate()); + } + + // Assign new random numbers + for (0..result.world_count) |i| { + result.worlds[i].randomnumber = randomWorldId(); + } + + // Build UNNEST update params + var ids_buf: [4096]u8 = undefined; + var rns_buf: [4096]u8 = undefined; + var ids_pos: usize = 0; + var rns_pos: usize = 0; + + ids_buf[0] = '{'; + ids_pos = 1; + rns_buf[0] = '{'; + rns_pos = 1; + + for (0..result.world_count) |i| { + if (i > 0) { + ids_buf[ids_pos] = ','; + ids_pos += 1; + rns_buf[rns_pos] = ','; + rns_pos += 1; + } + ids_pos += writeInt(ids_buf[ids_pos..], @intCast(result.worlds[i].id)); + rns_pos += writeInt(rns_buf[rns_pos..], @intCast(result.worlds[i].randomnumber)); + } + + ids_buf[ids_pos] = '}'; + ids_pos += 1; + ids_buf[ids_pos] = 0; + + rns_buf[rns_pos] = '}'; + rns_pos += 1; + rns_buf[rns_pos] = 0; + + // Submit the UPDATE as a follow-up request on the same connection + const ring = http.getAsyncPollRing() orelse { + return writeRawResponseAlloc("application/json", "[]", getCachedDate()); + }; + + const update_req = pg.DbRequest{ + .http_conn_ptr = conn_ptr, + .operation = .{ .raw_prepared = .{ + .stmt_name = "update_worlds", + .params = .{ @ptrCast(&ids_buf), @ptrCast(&rns_buf) }, + .n_params = 2, + } }, + .callback = updatesWriteCallback, + .result_data = result.*, // Copy the worlds data for the response + .phase = .updates_write, + .pipeline_results_remaining = 0, + .pipeline_results_consumed = 0, + .active = false, + }; + + // Submit to the pool — must not silently skip the UPDATE + if (!pool.submit(ring, update_req)) { + std.log.err("Updates: failed to submit UPDATE to pool", .{}); + return writeRawResponseAlloc("application/json", "{\"error\":\"pool full\"}", getCachedDate()); + } + + // Don't return a response yet — wait for the UPDATE to complete + return null; +} + +fn updatesWriteCallback(conn_ptr: usize, result: *pg.DbResult, phase: pg.async_pool.Phase, pool: *pg.DbConnPool) ?[]const u8 { + _ = conn_ptr; + _ = phase; + _ = pool; + + // UPDATE complete — send the worlds as JSON response + const worlds = worldsFromResult(result); + const body = writeWorldsJsonRaw(worlds); + return writeRawResponseAlloc("application/json", body, getCachedDate()); +} + +// ============================================================================ +// Helpers +// ============================================================================ + +fn getPool() ?*pg.DbConnPool { + const state = http.getAsyncPollState() orelse return null; + return @ptrCast(@alignCast(state)); +} + +fn parseQueryCount(ctx: *http.Context, param_name: []const u8) usize { + const raw = ctx.query(param_name) orelse return 1; + const n = std.fmt.parseInt(usize, raw, 10) catch return 1; + if (n < 1) return 1; + if (n > 500) return 500; + return n; +} + +fn worldsFromResult(result: *pg.DbResult) []const World { + // Cast pg.async_pool.World to our World (same layout) + const pg_worlds: [*]const pg.async_pool.World = &result.worlds; + const our_worlds: [*]const World = @ptrCast(pg_worlds); + return our_worlds[0..result.world_count]; +} + +threadlocal var tl_body_buf: [32768]u8 = undefined; + +fn writeWorldsJsonRaw(worlds: []const World) []const u8 { + var writer = http.JsonWriter.init(&tl_body_buf); + + writer.writeByte('[') catch unreachable; + for (worlds, 0..) |w, i| { + if (i > 0) writer.writeByte(',') catch unreachable; + writer.writeRaw("{\"id\":") catch unreachable; + writer.writeInt(w.id) catch unreachable; + writer.writeRaw(",\"randomnumber\":") catch unreachable; + writer.writeInt(w.randomnumber) catch unreachable; + writer.writeByte('}') catch unreachable; + } + writer.writeByte(']') catch unreachable; + + return writer.getWritten(); +} + +fn sendWorldsRaw(ctx: *http.Context, worlds: []const World) void { + const body = writeWorldsJsonRaw(worlds); + ctx.response.setRaw(writeRawResponse("application/json", body, getDate())); +} + +fn htmlEscape(out: []u8, input: []const u8) usize { + var pos: usize = 0; + for (input) |ch| { + switch (ch) { + '<' => { + @memcpy(out[pos..][0..4], "<"); + pos += 4; + }, + '>' => { + @memcpy(out[pos..][0..4], ">"); + pos += 4; + }, + '&' => { + @memcpy(out[pos..][0..5], "&"); + pos += 5; + }, + '"' => { + @memcpy(out[pos..][0..6], """); + pos += 6; + }, + '\'' => { + @memcpy(out[pos..][0..5], "'"); + pos += 5; + }, + else => { + out[pos] = ch; + pos += 1; + }, + } + } + return pos; +} + +// ============================================================================ +// Main +// ============================================================================ + +pub fn main() !void { + const allocator = std.heap.c_allocator; + + // Start cache refresh background thread + startCacheRefreshThread() catch |err| { + std.log.warn("Failed to start cache thread: {} (cached-queries will be unavailable)", .{err}); + }; + + // Create router + var router = http.router(allocator); + defer router.deinit(); + + _ = router + .get("/json", handleJson) + .get("/plaintext", handlePlaintext) + .get("/db", handleDb) + .get("/queries", handleQueries) + .get("/fortunes", handleFortunes) + .get("/updates", handleUpdates) + .get("/cached-queries", handleCachedQueries); + + var server = http.Server.init(allocator, &router, .{ + .threads = null, // Use CPU count + .ring_size = 4096, + .cqe_batch_size = 512, + .cpu_affinity = true, + .tcp_nodelay = true, + .max_connections = 8192, + .read_buffer_size = 4096, + .async_poll_init = asyncPollInit, + .async_poll_deinit = asyncPollDeinit, + .async_poll_handler = asyncPollHandler, + }); + defer server.deinit(); + + const port: u16 = if (std.fmt.parseInt(u16, std.posix.getenv("PORT") orelse "8080", 10)) |p| p else |_| 8080; + + std.log.info("TechEmpower benchmark server starting on port {d} (async DB mode)", .{port}); + std.log.info("Endpoints: /json /plaintext /db /queries /fortunes /updates /cached-queries", .{}); + try server.run("0.0.0.0", port); +} diff --git a/frameworks/Zig/zap/.gitignore b/frameworks/Zig/zap/.gitignore index 170dc0f1403..3389c86c994 100644 --- a/frameworks/Zig/zap/.gitignore +++ b/frameworks/Zig/zap/.gitignore @@ -1,2 +1,2 @@ -zig-cache/**/*', -zig-out: 'zig-out/**/*', +.zig-cache/ +zig-out/ diff --git a/frameworks/Zig/zap/benchmark_config.json b/frameworks/Zig/zap/benchmark_config.json index 0b77f27d77d..8ce89ab396e 100644 --- a/frameworks/Zig/zap/benchmark_config.json +++ b/frameworks/Zig/zap/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "zap", + "maintainers": ["dragosv"], "tests": [{ "default": { "json_url": "/json", diff --git a/frameworks/Zig/zap/build.zig b/frameworks/Zig/zap/build.zig index 2da55a07981..617ea757666 100644 --- a/frameworks/Zig/zap/build.zig +++ b/frameworks/Zig/zap/build.zig @@ -1,80 +1,41 @@ const std = @import("std"); -const ModuleMap = std.StringArrayHashMap(*std.Build.Module); -var gpa = std.heap.GeneralPurposeAllocator(.{}){}; -const allocator = gpa.allocator(); -// Although this function looks imperative, note that its job is to -// declaratively construct a build graph that will be executed by an external -// runner. -pub fn build(b: *std.Build) !void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. +pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); - - // Standard optimization options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do nots - // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); - const dep_opts = .{ .target = target, .optimize = optimize }; - - const exe = b.addExecutable(.{ - .name = "zap", - // In this case the main source file is merely a path, however, in more - // complicated build scripts, this could be a generated file. - .root_source_file = b.path("src/main.zig"), + const zap = b.dependency("zap", .{ .target = target, .optimize = optimize, + .openssl = false, }); - const zap = b.dependency("zap", .{ + const pg = b.dependency("pg", .{ .target = target, .optimize = optimize, - .openssl = false, // set to true to enable TLS support }); - var modules = ModuleMap.init(allocator); - defer modules.deinit(); - - const zap_module = b.dependency("zap", dep_opts).module("zap"); - const pg_module = b.dependency("pg", dep_opts).module("pg"); - - try modules.put("zap", zap_module); - try modules.put("pg", pg_module); - - // // Expose this as a module that others can import - exe.root_module.addImport("zap", zap_module); - exe.root_module.addImport("pg", pg_module); - - exe.linkLibrary(zap.artifact("facil.io")); + const exe = b.addExecutable(.{ + .name = "zap", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "zap", .module = zap.module("zap") }, + .{ .name = "pg", .module = pg.module("pg") }, + }, + }), + }); - // This declares intent for the executable to be installed into the - // standard location when the user invokes the "install" step (the default - // step when running `zig build`). b.installArtifact(exe); - // This *creates* a Run step in the build graph, to be executed when another - // step is evaluated that depends on it. The next line below will establish - // such a dependency. const run_cmd = b.addRunArtifact(exe); - - // By making the run step depend on the install step, it will be run from the - // installation directory rather than directly from within the cache directory. - // This is not necessary, however, if the application depends on other installed - // files, this ensures they will be present and in the expected location. run_cmd.step.dependOn(b.getInstallStep()); - - // This allows the user to pass arguments to the application in the build - // command itself, like this: `zig build run -- arg1 arg2 etc` if (b.args) |args| { run_cmd.addArgs(args); } - // This creates a build step. It will be visible in the `zig build --help` menu, - // and can be selected like this: `zig build run` - // This will evaluate the `run` step rather than the default, which is "install". const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); } diff --git a/frameworks/Zig/zap/build.zig.zon b/frameworks/Zig/zap/build.zig.zon index 3f492b7d954..80e2b69f948 100644 --- a/frameworks/Zig/zap/build.zig.zon +++ b/frameworks/Zig/zap/build.zig.zon @@ -1,12 +1,20 @@ -.{ .name = "Zap testing", .version = "0.1.1", .paths = .{ - "build.zig", - "build.zig.zon", - "src", -}, .dependencies = .{ - .zap = .{ - .url = "https://github.com/zigzap/zap/archive/refs/tags/v0.8.0.tar.gz", - .hash = "12209936c3333b53b53edcf453b1670babb9ae8c2197b1ca627c01e72670e20c1a21", +.{ + .name = .zap_testing, + .version = "0.2.1", + .fingerprint = 0x40157312a106e70e, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", }, - .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", - .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, -} } + .dependencies = .{ + .zap = .{ + .url = "git+https://github.com/zigzap/zap?ref=v0.11.0#66c5dc42c781bbb8a9100afda3c7e69ee96eddf3", + .hash = "zap-0.10.6-GoeB8xCEJABLgoiZjWZMMT5TsoZ5OO2EZe6j24RTUYEH", + }, + .pg = .{ + .url = "git+https://github.com/karlseguin/pg.zig?ref=master#e58b318b7867ef065b3135983f829219c5eef891", + .hash = "pg-0.0.0-Wp_7gXFoBgD0fQ72WICKa-bxLga03AXXQ3BbIsjjohQ3", + }, + }, +} diff --git a/frameworks/Zig/zap/src/endpoints.zig b/frameworks/Zig/zap/src/endpoints.zig index 44a3afc43e2..4f39049ecf2 100644 --- a/frameworks/Zig/zap/src/endpoints.zig +++ b/frameworks/Zig/zap/src/endpoints.zig @@ -2,7 +2,7 @@ const std = @import("std"); const zap = @import("zap"); const pg = @import("pg"); -const Mustache = @import("zap").Mustache; +const Mustache = zap.Mustache; const Thread = std.Thread; const Mutex = Thread.Mutex; @@ -23,7 +23,7 @@ const Fortune = struct { }; pub const FortunesEndpoint = struct { - ep: zap.Endpoint = undefined, + path: []const u8 = "/fortunes", mustache: Mustache, mutex: Mutex, @@ -34,10 +34,6 @@ pub const FortunesEndpoint = struct { const mustache = Mustache.fromData(template) catch unreachable; return .{ - .ep = zap.Endpoint.init(.{ - .path = "/fortunes", - .get = get, - }), .mustache = mustache, .mutex = Mutex{}, }; @@ -47,37 +43,30 @@ pub const FortunesEndpoint = struct { self.mustache.deinit(); } - pub fn endpoint(self: *Self) *zap.Endpoint { - return &self.ep; - } - - fn compareStrings(_: void, lhs: []const u8, rhs: []const u8) bool { - return std.mem.order(u8, lhs, rhs).compare(std.math.CompareOperator.lt); - } - fn cmpFortuneByMessage(_: void, a: Fortune, b: Fortune) bool { return std.mem.order(u8, a.message, b.message).compare(std.math.CompareOperator.lt); } fn getFortunes(pool: *pg.Pool) ![]const Fortune { + const alloc = middleware.SharedAllocator.getAllocator(); var conn = try pool.acquire(); defer conn.release(); var rows = try conn.query("SELECT id, message FROM Fortune", .{}); defer rows.deinit(); - var fortunes = std.ArrayList(Fortune).init(middleware.SharedAllocator.getAllocator()); - defer fortunes.deinit(); + var fortunes: std.ArrayListUnmanaged(Fortune) = .empty; + defer fortunes.deinit(alloc); while (try rows.next()) |row| { - const fortune = Fortune{ .id = row.get(i32, 0), .message = row.get([]const u8, 1) }; - try fortunes.append(fortune); + const fortune = Fortune{ .id = try row.get(i32, 0), .message = try row.get([]const u8, 1) }; + try fortunes.append(alloc, fortune); } const fortune = Fortune{ .id = 0, .message = "Additional fortune added at request time." }; - try fortunes.append(fortune); + try fortunes.append(alloc, fortune); - const fortunes_slice = try fortunes.toOwnedSlice(); + const fortunes_slice = try fortunes.toOwnedSlice(alloc); std.mem.sort(Fortune, fortunes_slice, {}, cmpFortuneByMessage); return fortunes_slice; @@ -92,22 +81,13 @@ pub const FortunesEndpoint = struct { self.mutex.unlock(); const raw = ret.str().?; - - // std.debug.print("mustache output {s}\n", .{raw}); - const html = try deescapeHtml(raw); - // std.debug.print("html output {s}\n", .{html}); - return html; } - pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self: *FortunesEndpoint = @fieldParentPtr("ep", ep); - - if (!checkPath(ep, req)) return; - - req.setHeader("content-type", "text/html; charset=utf-8") catch return; + pub fn get(self: *Self, req: zap.Request) !void { + try req.setHeader("content-type", "text/html; charset=utf-8"); var pool: *pg.Pool = undefined; @@ -118,39 +98,26 @@ pub const FortunesEndpoint = struct { } } - const fortunes_html = getFortunesHtml(self, pool) catch return; + const fortunes_html = try self.getFortunesHtml(pool); - req.sendBody(fortunes_html) catch return; - - return; + try req.sendBody(fortunes_html); } }; pub const DbEndpoint = struct { - ep: zap.Endpoint = undefined, + path: []const u8 = "/db", mutex: Mutex, + const Self = @This(); pub fn init() Self { return .{ - .ep = zap.Endpoint.init(.{ - .path = "/db", - .get = get, - }), .mutex = Mutex{}, }; } - pub fn endpoint(self: *Self) *zap.Endpoint { - return &self.ep; - } - - pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self: *DbEndpoint = @fieldParentPtr("ep", ep); - - if (!checkPath(ep, req)) return; - - req.setContentType(.JSON) catch return; + pub fn get(self: *Self, req: zap.Request) !void { + try req.setContentType(.JSON); var random_number: u32 = 0; var pool: *pg.Pool = undefined; @@ -172,17 +139,12 @@ pub const DbEndpoint = struct { return; } - const json_to_send = getJson(pool, random_number) catch |err| { - std.debug.print("Error querying database: {}\n", .{err}); - return; - }; - - req.sendBody(json_to_send) catch return; + const json_to_send = try getJson(pool, random_number); - return; + try req.sendBody(json_to_send); } - fn getJson(pool: *pg.Pool, random_number: u32) ![]const u8{ + fn getJson(pool: *pg.Pool, random_number: u32) ![]const u8 { var conn = try pool.acquire(); defer conn.release(); @@ -191,149 +153,97 @@ pub const DbEndpoint = struct { var row = row_result.?; defer row.deinit() catch {}; - const world = World{ .id = row.get(i32, 0), .randomNumber = row.get(i32, 1) }; + const world = World{ .id = try row.get(i32, 0), .randomNumber = try row.get(i32, 1) }; var buf: [100]u8 = undefined; - var json_to_send: []const u8 = undefined; - if (zap.stringifyBuf(&buf, world, .{})) |json_message| { - json_to_send = json_message; - } else { - json_to_send = "null"; - } - + const json_to_send = zap.util.stringifyBuf(&buf, world, .{}) catch return "null"; return json_to_send; } }; pub const PlaintextEndpoint = struct { - ep: zap.Endpoint = undefined, + path: []const u8 = "/plaintext", + const Self = @This(); pub fn init() Self { - return .{ - .ep = zap.Endpoint.init(.{ - .path = "/plaintext", - .get = get, - }), - }; - } - - pub fn endpoint(self: *Self) *zap.Endpoint { - return &self.ep; + return .{}; } - pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self: *PlaintextEndpoint = @fieldParentPtr("ep", ep); - _ = self; - - if (!checkPath(ep, req)) return; - - req.setContentType(.TEXT) catch return; - - req.sendBody("Hello, World!") catch return; - return; + pub fn get(_: *Self, req: zap.Request) !void { + try req.setContentType(.TEXT); + try req.sendBody("Hello, World!"); } }; pub const JsonEndpoint = struct { - ep: zap.Endpoint = undefined, + path: []const u8 = "/json", + const Self = @This(); pub fn init() Self { - return .{ - .ep = zap.Endpoint.init(.{ - .path = "/json", - .get = get, - }), - }; - } - - pub fn endpoint(self: *Self) *zap.Endpoint { - return &self.ep; + return .{}; } - pub fn get(ep: *zap.Endpoint, req: zap.Request) void { - const self: *JsonEndpoint = @fieldParentPtr("ep", ep); - _ = self; - - if (!checkPath(ep, req)) return; - - req.setContentType(.JSON) catch return; + pub fn get(_: *Self, req: zap.Request) !void { + try req.setContentType(.JSON); const message = Message{ .message = "Hello, World!" }; var buf: [100]u8 = undefined; - var json_to_send: []const u8 = undefined; - if (zap.stringifyBuf(&buf, message, .{})) |json_message| { - json_to_send = json_message; - } else { - json_to_send = "null"; - } - - req.sendBody(json_to_send) catch return; - return; + const json_to_send = zap.util.stringifyBuf(&buf, message, .{}) catch "null"; + try req.sendBody(json_to_send); } }; -fn checkPath(ep: *zap.Endpoint, req: zap.Request) bool { - if (!std.mem.eql(u8, ep.settings.path, req.path.?)) { - // std.debug.print("Path mismatch: {s} != {s}\n", .{ ep.settings.path, req.path.? }); - - return false; - } - - // std.debug.print("Path match: {s} == {s}\n", .{ ep.settings.path, req.path.? }); - - return true; -} - fn deescapeHtml(input: []const u8) ![]const u8 { - var output = std.ArrayList(u8).init(middleware.SharedAllocator.getAllocator()); - defer output.deinit(); + const alloc = middleware.SharedAllocator.getAllocator(); + var output: std.ArrayListUnmanaged(u8) = .empty; + defer output.deinit(alloc); var i: usize = 0; while (i < input.len) { if (std.mem.startsWith(u8, input[i..], " ")) { - try output.append(' '); + try output.append(alloc, ' '); i += 5; } else if (std.mem.startsWith(u8, input[i..], """)) { - try output.append('"'); + try output.append(alloc, '"'); i += 5; } else if (std.mem.startsWith(u8, input[i..], "&")) { - try output.append('&'); + try output.append(alloc, '&'); i += 5; } else if (std.mem.startsWith(u8, input[i..], "'")) { - try output.append('\''); + try output.append(alloc, '\''); i += 5; } else if (std.mem.startsWith(u8, input[i..], "(")) { - try output.append('('); + try output.append(alloc, '('); i += 5; } else if (std.mem.startsWith(u8, input[i..], ")")) { - try output.append(')'); + try output.append(alloc, ')'); i += 5; } else if (std.mem.startsWith(u8, input[i..], "+")) { - try output.append('+'); + try output.append(alloc, '+'); i += 5; } else if (std.mem.startsWith(u8, input[i..], ",")) { - try output.append(','); + try output.append(alloc, ','); i += 5; } else if (std.mem.startsWith(u8, input[i..], ".")) { - try output.append('.'); + try output.append(alloc, '.'); i += 5; } else if (std.mem.startsWith(u8, input[i..], "/")) { - try output.append('/'); + try output.append(alloc, '/'); i += 5; } else if (std.mem.startsWith(u8, input[i..], ":")) { - try output.append(':'); + try output.append(alloc, ':'); i += 5; } else if (std.mem.startsWith(u8, input[i..], ";")) { - try output.append(';'); + try output.append(alloc, ';'); i += 5; } else { - try output.append(input[i]); + try output.append(alloc, input[i]); i += 1; } } - return output.toOwnedSlice(); + return output.toOwnedSlice(alloc); } diff --git a/frameworks/Zig/zap/src/main.zig b/frameworks/Zig/zap/src/main.zig index e2792726f04..2c1702b5faf 100644 --- a/frameworks/Zig/zap/src/main.zig +++ b/frameworks/Zig/zap/src/main.zig @@ -1,14 +1,11 @@ const std = @import("std"); -const builtin = @import("builtin"); const zap = @import("zap"); const pg = @import("pg"); -const regex = @import("regex"); const pool = @import("pool.zig"); const endpoints = @import("endpoints.zig"); const middleware = @import("middleware.zig"); -const RndGen = std.rand.DefaultPrng; const Allocator = std.mem.Allocator; const Pool = pg.Pool; @@ -16,12 +13,7 @@ pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true, }){}; - - var tsa = std.heap.ThreadSafeAllocator{ - .child_allocator = gpa.allocator(), - }; - - const allocator = tsa.allocator(); + const allocator = gpa.allocator(); var zap_port: []u8 = undefined; var arg_string = try std.fmt.allocPrint(allocator, "{s}", .{"0"}); @@ -31,8 +23,7 @@ pub fn main() !void { defer args.deinit(); while (args.next()) |arg| { arg_string = try std.fmt.allocPrint(allocator, "{s}", .{arg}); - - zap_port = arg_string; // use arg + zap_port = arg_string; } var port = try std.fmt.parseInt(u16, zap_port, 0); @@ -44,39 +35,39 @@ pub fn main() !void { var pg_pool = try pool.initPool(allocator); defer pg_pool.deinit(); - var prng = std.rand.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp()))); + var prng = std.Random.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp()))); middleware.SharedAllocator.init(allocator); - // create the endpoint + // create the endpoints var dbEndpoint = endpoints.DbEndpoint.init(); var plaintextEndpoint = endpoints.PlaintextEndpoint.init(); var jsonEndpoint = endpoints.JsonEndpoint.init(); var fortunesEndpoint = endpoints.FortunesEndpoint.init(); - // we wrap the endpoint with a middleware handler - var jsonEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, middleware.Context).init( - jsonEndpoint.endpoint(), // the endpoint - null, // no other handler (we are the last in the chain) - false, // break on finish. See EndpointHandler for this. Not applicable here. + // we wrap the endpoints with middleware handlers + var jsonEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, endpoints.JsonEndpoint, middleware.Context).init( + &jsonEndpoint, + null, + .{ .checkPath = true }, ); - var plaintextEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, middleware.Context).init( - plaintextEndpoint.endpoint(), + var plaintextEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, endpoints.PlaintextEndpoint, middleware.Context).init( + &plaintextEndpoint, jsonEndpointHandler.getHandler(), - false, + .{ .checkPath = true }, ); - var fortunesEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, middleware.Context).init( - fortunesEndpoint.endpoint(), // the endpoint - plaintextEndpointHandler.getHandler(), // no other handler (we are the last in the chain) - false, + var fortunesEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, endpoints.FortunesEndpoint, middleware.Context).init( + &fortunesEndpoint, + plaintextEndpointHandler.getHandler(), + .{ .checkPath = true }, ); - var dbEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, middleware.Context).init( - dbEndpoint.endpoint(), // the endpoint - fortunesEndpointHandler.getHandler(), // no other handler (we are the last in the chain) - false, + var dbEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, endpoints.DbEndpoint, middleware.Context).init( + &dbEndpoint, + fortunesEndpointHandler.getHandler(), + .{ .checkPath = true }, ); var headerHandler = middleware.HeaderMiddleWare.init(dbEndpointHandler.getHandler()); @@ -85,22 +76,19 @@ pub fn main() !void { var listener = try zap.Middleware.Listener(middleware.Context).init( .{ - .on_request = null, // must be null + .on_request = null, .port = port, .log = false, .max_clients = 100000, }, pgHandler.getHandler(), - middleware.SharedAllocator.getAllocator, ); try listener.listen(); - //const cpuCount = @as(i16, @intCast(std.Thread.getCpuCount() catch 1)); - //const workers = if (builtin.mode == .Debug) 1 else cpuCount; const threads = 128; - std.debug.print("Listening at 0.0.0.0:{d} on {d} threads\n", .{port, threads}); + std.debug.print("Listening at 0.0.0.0:{d} on {d} threads\n", .{ port, threads }); // start worker threads zap.start(.{ diff --git a/frameworks/Zig/zap/src/middleware.zig b/frameworks/Zig/zap/src/middleware.zig index 99fb9255c0c..c134ba7a5f7 100644 --- a/frameworks/Zig/zap/src/middleware.zig +++ b/frameworks/Zig/zap/src/middleware.zig @@ -7,8 +7,6 @@ pub const SharedAllocator = struct { // static var allocator: std.mem.Allocator = undefined; - const Self = @This(); - // just a convenience function pub fn init(a: std.mem.Allocator) void { allocator = a; @@ -45,12 +43,12 @@ pub const HeaderMiddleWare = struct { } // note that the first parameter is of type *Handler, not *Self !!! - pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) bool { + pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) !bool { // this is how we would get our self pointer const self: *Self = @fieldParentPtr("handler", handler); _ = self; - req.setHeader("Server", "Zap") catch return false; + try req.setHeader("Server", "Zap"); // continue in the chain return handler.handleOther(req, context); @@ -59,15 +57,15 @@ pub const HeaderMiddleWare = struct { pub const RandomMiddleWare = struct { handler: Handler, - rnd: *std.rand.DefaultPrng, + rnd: *std.Random.DefaultPrng, const Self = @This(); - const Prng = struct { - rnd: *std.rand.DefaultPrng = undefined, + pub const Prng = struct { + rnd: *std.Random.DefaultPrng = undefined, }; - pub fn init(other: ?*Handler, rnd: *std.rand.DefaultPrng) Self { + pub fn init(other: ?*Handler, rnd: *std.Random.DefaultPrng) Self { return .{ .handler = Handler.init(onRequest, other), .rnd = rnd, @@ -80,8 +78,7 @@ pub const RandomMiddleWare = struct { } // note that the first parameter is of type *Handler, not *Self !!! - pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) bool { - + pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) !bool { // this is how we would get our self pointer const self: *RandomMiddleWare = @fieldParentPtr("handler", handler); @@ -98,7 +95,7 @@ pub const PgMiddleWare = struct { const Self = @This(); - const Pg = struct { + pub const Pg = struct { pool: *pg.Pool = undefined, }; @@ -115,8 +112,7 @@ pub const PgMiddleWare = struct { } // note that the first parameter is of type *Handler, not *Self !!! - pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) bool { - + pub fn onRequest(handler: *Handler, req: zap.Request, context: *Context) !bool { // this is how we would get our self pointer const self: *Self = @fieldParentPtr("handler", handler); diff --git a/frameworks/Zig/zap/src/pool.zig b/frameworks/Zig/zap/src/pool.zig index 6615ae217ce..de18e15c510 100644 --- a/frameworks/Zig/zap/src/pool.zig +++ b/frameworks/Zig/zap/src/pool.zig @@ -1,16 +1,11 @@ const std = @import("std"); -const regex = @import("regex"); -const dns = @import("dig"); const pg = @import("pg"); const Allocator = std.mem.Allocator; const Pool = pg.Pool; -const ArrayList = std.ArrayList; -const Regex = regex.Regex; pub fn initPool(allocator: Allocator) !*pg.Pool { const info = try parsePostgresConnStr(allocator); - //std.debug.print("Connection: {s}:{s}@{s}:{d}/{s}\n", .{ info.username, info.password, info.hostname, info.port, info.database }); const pg_pool = try Pool.init(allocator, .{ .size = 28, @@ -22,8 +17,8 @@ pub fn initPool(allocator: Allocator) !*pg.Pool { .username = info.username, .database = info.database, .password = info.password, + .timeout = 10_000, }, - .timeout = 10_000, }); return pg_pool; @@ -37,30 +32,8 @@ pub const ConnectionInfo = struct { database: []const u8, }; -fn addressAsString(address: std.net.Address) ![]const u8 { - const bytes = @as(*const [4]u8, @ptrCast(&address.in.sa.addr)); - - var buffer: [256]u8 = undefined; - var source = std.io.StreamSource{ .buffer = std.io.fixedBufferStream(&buffer) }; - var writer = source.writer(); - - //try writer.writeAll("Hello, World!"); - - try writer.print("{}.{}.{}.{}", .{ - bytes[0], - bytes[1], - bytes[2], - bytes[3], - }); - - const output = source.buffer.getWritten(); - - return output; -} - fn parsePostgresConnStr(allocator: Allocator) !ConnectionInfo { const pg_port = try getEnvVar(allocator, "PG_PORT", "5432"); - // std.debug.print("tfb port {s}\n", .{pg_port}); var port = try std.fmt.parseInt(u16, pg_port, 0); if (port == 0) { diff --git a/frameworks/Zig/zap/zap.dockerfile b/frameworks/Zig/zap/zap.dockerfile index 71123f4f3e7..2a7c31572d0 100644 --- a/frameworks/Zig/zap/zap.dockerfile +++ b/frameworks/Zig/zap/zap.dockerfile @@ -1,4 +1,4 @@ -FROM fedora:40 AS build +FROM fedora:42 WORKDIR /zap @@ -11,20 +11,28 @@ ENV PG_PORT=5432 COPY src src COPY build.zig.zon build.zig.zon COPY build.zig build.zig + +RUN dnf install -y tar xz git wget nginx + +ARG ZIG_VER=0.15.2 + +RUN wget https://ziglang.org/download/${ZIG_VER}/zig-$(uname -m)-linux-${ZIG_VER}.tar.xz + +RUN tar -xvf zig-$(uname -m)-linux-${ZIG_VER}.tar.xz + +RUN mv zig-$(uname -m)-linux-${ZIG_VER} /usr/local/zig + +ENV PATH="/usr/local/zig:$PATH" COPY start-servers.sh start-servers.sh COPY build-nginx-conf.sh build-nginx-conf.sh COPY nginx.conf nginx.conf -RUN chmod +x start-servers.sh -RUN chmod +x build-nginx-conf.sh - -RUN ./build-nginx-conf.sh +RUN chmod +x start-servers.sh build-nginx-conf.sh && ./build-nginx-conf.sh -RUN dnf install -y zig nginx RUN zig version -RUN zig build -Doptimize=ReleaseFast +RUN zig build -Doptimize=ReleaseFast RUN cp /zap/zig-out/bin/zap /usr/local/bin EXPOSE 8080 -CMD ./start-servers.sh && nginx -c /zap/nginx.conf -g "daemon off;" \ No newline at end of file +CMD ./start-servers.sh && nginx -c /zap/nginx.conf -g "daemon off;" diff --git a/toolset/databases/mongodb/mongodb.dockerfile b/toolset/databases/mongodb/mongodb.dockerfile index 11480684535..0059551b103 100644 --- a/toolset/databases/mongodb/mongodb.dockerfile +++ b/toolset/databases/mongodb/mongodb.dockerfile @@ -1,5 +1,6 @@ FROM mongo:8.0 ENV MONGO_INITDB_DATABASE=hello_world +ENV MONGO_TCMALLOC_PER_CPU_CACHE_SIZE_BYTES=16777216 COPY create.js /docker-entrypoint-initdb.d/ diff --git a/toolset/databases/mysql/mysql.dockerfile b/toolset/databases/mysql/mysql.dockerfile index b5c5b6a67bb..52df810216b 100644 --- a/toolset/databases/mysql/mysql.dockerfile +++ b/toolset/databases/mysql/mysql.dockerfile @@ -1,4 +1,4 @@ -FROM mysql:9.0 +FROM mysql:9.4 ENV MYSQL_ROOT_PASSWORD=root ENV MYSQL_USER=benchmarkdbuser diff --git a/toolset/scaffolding/benchmark_config.json b/toolset/scaffolding/benchmark_config.json index 7eb95788afd..63ac1fd6ad1 100644 --- a/toolset/scaffolding/benchmark_config.json +++ b/toolset/scaffolding/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "$NAME", + "maintainers": [], "tests": [ { "default": { @@ -19,7 +20,8 @@ "database_os": "Linux", "display_name": "$DISPLAY_NAME", "notes": "", - "versus": "$VERSUS" + "versus": "$VERSUS", + "tags": [] } } ] diff --git a/toolset/utils/metadata.py b/toolset/utils/metadata.py index 6f7388828b8..21530676287 100644 --- a/toolset/utils/metadata.py +++ b/toolset/utils/metadata.py @@ -184,7 +184,7 @@ def parse_config(self, config, directory): # Loop over them and parse each into a FrameworkTest for test in config['tests']: - tests_to_run = [name for (name, keys) in test.items()] + tests_to_run = test.keys() if "default" not in tests_to_run: log("Framework %s does not define a default test in benchmark_config.json" @@ -193,8 +193,8 @@ def parse_config(self, config, directory): # Check that each framework does not have more than the maximum number of tests maximum_tests = 10 - non_broken_tests_filter = lambda test: (not hasattr(test, "tags")) or ("broken" not in test.tags) - non_broken_tests_to_run = list(filter(non_broken_tests_filter, tests_to_run)) + non_broken_tests_filter = lambda test: (not ("tags" in test.keys() and ("broken" in test["tags"]))) + non_broken_tests_to_run = list(filter(non_broken_tests_filter, test.values())) if len(non_broken_tests_to_run) > maximum_tests: message = [ "Framework %s defines %s tests in benchmark_config.json (max is %s)."